pdlc-design
创建技术设计文档(自动生成 + 自检 + handoff)
Install
npx skills add https://github.com/kanfu-panda/pdlc-skills/tree/main/skills/pdlc-design
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install kanfu-panda-pdlc-skills@llmmart
git clone https://github.com/kanfu-panda/pdlc-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole kanfu-panda/pdlc-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
创建设计文档
⛔ IRON LAW · 不可违反的硬门禁
以下规则为不可协商的执行约束:
- 文件必须落盘:所有带编号(功能ID / 缺陷ID)的文档,必须作为实际文件写入磁盘,不可仅在对话中输出。
- 阶段必须落章:每个阶段完成后必须在状态机
docs/.pdlc-state/<feature-id>.json追加 history,不可跳过。 - 测试必须存在:进入
/pdlc-implement前,对应测试必须存在且处于红灯状态。违反则中止。 - 自检必须执行:段二自检为强制步骤,不得以"已经很好了"为由跳过。
- 防循环:段三修复为单次,不递归。无法自动修复的问题记录到报告,继续往下走。
- 状态必推进:成功执行某 phase 后
current_stage必须变更。收尾时若发现current_stage未推进,视为失败并报错,不得静默返回(防止外层循环拿滞后的状态空转烧额度)。唯一例外:命中人工点主动 block 时,current_stage保持不变但必须写last_phase_result.ok=false+blocked_reason。
违反任一条 = 立即中止当前命令,输出违规详情,等待人工介入。
根据已有的需求文档,在 docs/02_design/ 对应子目录下创建技术设计文档。
输入解析
从本命令的参数中判断输入类型:
- 文件路径(以
/、./开头,或以.md、.txt、.pdf结尾,或实际存在的文件):直接读取该文件作为需求来源,跳过 PRD 搜索 - 功能名关键词(默认):按下方守卫检查搜索 PRD
PDLC 前置检查(必须执行,不可跳过)
- 若输入为文件路径,直接读取文件内容作为需求,提取功能名和功能ID(如有),跳到步骤 4
- 从用户输入中提取功能名称关键词
- 在
docs/01_requirements/prd/目录下搜索包含该关键词的 PRD 文档- 匹配新格式:
F<日期>-<编号>-*<关键词>*-prd.md - 匹配旧格式:
YYYYMMDD-*<关键词>*-prd.md - 同时检查文件内容中是否包含该关键词
- 匹配新格式:
- 未找到 → 输出以下信息后立即停止,不继续执行:
⛔ PDLC 守卫:未找到与「<功能名>」相关的 PRD 文档。 设计文档必须基于已有的 PRD。请先运行: 👉 /pdlc-prd <需求描述> - 找到 → 提取功能ID(如
F20260326-090000),读取该 PRD 内容,继续执行
输出位置
- API 设计 →
docs/02_design/api/ - 架构设计 →
docs/02_design/architecture/ - 数据库设计 →
docs/02_design/database/
要求
- 先阅读找到的 PRD 文档,全面理解需求
- 参考 本 skill 目录下的
assets/api-design-template.md获取 API 设计模板格式 - 参考
docs/00_standards/目录了解项目规范(未命中 → 提示consider /pdlc-standard add <category>/<topic>) - 文件名格式:
<功能ID>-<功能名>-<类型>.md(如F20260326-090000-user-auth-api.md),类型可以是 api / arch / db- 若 PRD 为旧格式无功能ID,则使用旧格式
YYYYMMDD-<功能名>-<类型>.md
- 若 PRD 为旧格式无功能ID,则使用旧格式
- 文档顶部必须包含 PDLC 追溯头:
<!-- PDLC-TRACE --> <!-- 功能ID: F20260326-090000 --> <!-- 功能名称: user-auth --> <!-- 阶段: 设计 --> <!-- 前置文档: docs/01_requirements/prd/F20260326-090000-user-auth-prd.md -->
🌐 Output language for generated artifacts
All generated artifacts (PRDs, design docs, code comments, review reports, test plans, deployment manuals, changelog entries, etc.) follow this policy:
Default — match the conversation language exactly:
- 用户用中文与 Claude 对话 → 产中文文档、中文代码注释、中文报告
- User talks to Claude in English → produce English artifacts
- User talks in another language → produce artifacts in that language
- Never silently default to a fixed language regardless of the user's input.
Explicit override always wins: when the user specifies a language for an artifact (e.g. "write the PRD in English", "用英文写 API 设计文档", "output the deploy doc in Japanese"), use that language for that artifact, regardless of conversation language.
Mixed-language requirements: if the user wants some artifacts in one language and others in a different language (common: Chinese PRD + English API docs for partners), honour each per-artifact instruction.
Uncertain: if you cannot reliably detect the conversation language, ask once before producing the first artifact.
This policy applies to content (prose, comments, headings). It does not override technical conventions like English variable names, English git commit subjects, or English error codes when the project's conventions require them.
必须包含:概述、接口/架构/表结构定义、错误码/异常处理、数据模型
API 设计需遵循 RESTful 规范,统一响应格式
{ code, message, data }设计文档自审与自动修复(每份设计文档创建后立即执行,不可跳过):
- 重新阅读刚创建的设计文档,对照 PRD 逐项检查以下质量门禁:
PRD 一致性检查:
- PRD 中每条 P0/P1 功能是否都有对应的设计覆盖(接口/表结构/架构组件)
- 接口的入参/出参是否与 PRD 描述的功能行为一致
- 错误码是否覆盖了 PRD 中列出的异常场景
API 设计检查(如有 API 文档):
- 接口 URL 命名是否遵循 RESTful 规范(名词复数、层级清晰)
- 请求/响应结构是否完整(无缺失字段)
- 统一响应格式
{ code, message, data }是否一致执行 - 分页接口是否有 page/pageSize/total 参数
- 鉴权方式是否明确说明
数据库设计检查(如有 DB 文档):
- 每张表是否有主键定义
- 外键关系是否与 ER 图一致
- 常用查询字段是否有索引设计
- 是否有
created_at、updated_at等审计字段 - 迁移 DDL 是否完整可执行
跨文档一致性检查(如同时有 API + DB 文档):
- API 响应字段是否与数据库字段对应(字段名、类型)
- API 的查询/筛选参数是否有对应的数据库索引支撑
自动修复:
- PRD 功能遗漏:自动补充对应的接口/表设计
- 缺失的错误码:根据接口行为自动补充常见错误码(400/401/403/404/409/500)
- 缺失的索引:根据查询模式自动补充索引设计
- 缺失的审计字段:自动添加
created_at、updated_at - 缺失的分页参数:自动补充列表接口的分页设计
- 修复后在文档末尾追加审查记录:
## 自审记录 - 审查时间:<ISO 8601> - 对照 PRD:<PRD 文件路径> - 发现问题:X 项 - 自动修复:X 项 - 修复明细: - [已修复] <问题描述>
创建完成后,提示用户下一步是编写测试用例(
/pdlc-tdd <功能名>)
设计目标: $ARGUMENTS
本命令的状态机取值:阶段短名
design(写进history[].stage与last_phase_result.stage);下一跳pdlc-tdd(写进next_step,交接时提示)。
状态机更新(段四必须执行)
本命令完成主产出后,必须更新状态机文件 docs/.pdlc-state/<feature-id>.json。
文件格式
{
"feature_id": "<F/B ID>",
"feature_name": "<kebab-case>",
"created_at": "<首次创建时间 ISO 8601>",
"current_stage": "<当前阶段名>",
"run_mode": "interactive | autonomous",
"history": [
{
"stage": "<阶段名>",
"done_at": "<ISO 8601>",
"produced": ["<相对路径 1>", "<相对路径 2>"],
"self_audit": { "passed": <N>, "failed": <N>, "manual": <N> },
"auto_decisions": [
{ "point": "<autonomous 下自动前进的确认点>", "chose": "<所选默认>", "at": "<ISO 8601>" }
]
}
],
"last_phase_result": {
"stage": "<本次阶段名>",
"ok": true,
"advanced_to": "<推进到的下一阶段 | null>",
"checks": {},
"self_audit": { "failed": 0 },
"blocked_reason": null,
"run_mode": "interactive | autonomous",
"at": "<ISO 8601>"
},
"relations": {
"extends": [],
"depends_on": [],
"supersedes": [],
"resolves": [],
"conflicts_with": [],
"relates_to": [],
"_updated_at": "<ISO 8601 | 省略>"
},
"next_step": "<下一跳命令名,如 pdlc-design;若流程结束则为 null>"
}
⛔ 示例里的
"checks": {}是「本阶段没有命令可跑」的样子,不是键名示范——键名与取值见下方 §1。
relations块(RFC#6,Phase 1 可选,Phase 2 推荐):6 个 key 对应 6 种关系类型,各为 ID 数组,存出边。其中conflicts_with/relates_to是对称类型,两端都要写;其余四种有向,只写在源 feature 上。拿不准时用/pdlc-relate set写入,它会按规则校验。旧状态文件无此块时视为全空,向后兼容。入边由/pdlc-relate rebuild派生到_relations.json,不在此块手维护。
⛔ 写状态机的四条硬约束——读侧(
/pdlc-status、/pdlc-retro、/pdlc-relate)会逐条体检, 违反的每一处都会出现在它们输出的最前面:
- 实例里不写
terminal_state。skill frontmatter 的terminal_state:是「这个命令走完后应到达的终态名」, 不是状态字段。判终态只看current_stage是否以_done结尾。history[].stage写本命令的阶段短名(见本命令正文里「本命令的状态机取值」)——pdlc-implement写impl, 不写implement/implementation;pdlc-prd写requirements,不写prd。- 时间戳必须带时刻:
created_at/done_at/at一律写完整 ISO 8601(如2026-07-28T10:40:00+08:00)。 只写日期,同一天内的阶段耗时就全部算成 0——读侧只能记「不可测」。next_step只写命令名或null,不附说明文字(如「pdlc-ship(等评审通过)」)。 要说明原因,阻塞时写进last_phase_result.blocked_reason。
⛔
_done的含义是「已发布」,只由/pdlc-ship(写ship_done)与/pdlc-deploy(写deploy_done)写入。 其它命令的current_stage一律写本命令的阶段短名,走完整条链路的编排命令(/pdlc-feature)也一样—— 它收尾时current_stage是最后一个阶段的短名,next_step是pdlc-ship。
- 「评审通过、等待发布」就是
current_stage为review(或e2e等)且next_step为pdlc-ship。 循环相关文档里说的review_done指的就是这个状态,不是要写进current_stage的值。- 为什么:读侧判「已抵达终态」只看
current_stage是否以_done结尾。评审通过就写_done,/pdlc-ship就分不清哪些功能已经发布过,发布说明会重复或漏收。- 旧版本写入的
feature_done/fix_done/review_done分不清是否已发布,/pdlc-ship会列出来请人确认。
更新流程
- 文件不存在 → 创建文件,写入初始结构(
history为含当前阶段的数组) - 文件存在 → 读取 JSON,追加当前阶段到
history,更新current_stage和next_step - 写回文件:用
jq或等效工具保持格式化
⚠️ 若更新失败(文件损坏/权限问题),必须中止命令并在最终报告中报错。状态机不可跳过。
last_phase_result(机器可读阶段结果,每个 phase 收尾必写)
顶层 last_phase_result 是循环判停的唯一真源,外层只需 jq '.last_phase_result.ok' 即可决定 继续 / 停止 / 交还人类。规则:
checks必须客观、真跑得来:只放真跑命令的退出码结果(命令取自docs/00_standards/test-commands.yml,见test-commands-template.yml),绝不用模型自评、绝不填占位。有测试的阶段用tests_pass/coverage_pass/lint_clean(退出码 0 →true,非 0 →false);stage 语义不同用对应键(如 tdd 段{ "red_verified": true }表示红灯已验证)。⛔ 键名与类型都是契约的一部分:键名只能是
tests_pass/coverage_pass/lint_clean/e2e_pass(tdd 段red_verified),值只能是布尔。 最常见的两种错法:① 照抄test-commands.yml的unit/coverage/lint/e2e——那是命令表的字段名,不是状态机的(跑unit得到的结论写进tests_pass); ② 写成"4 passed, 1 failed"这类字符串摘要。两种都会让jq '.checks.tests_pass'读回null,消费方(发布闸门、质量报告、自主循环)只看到「无法判定」—— 你诚实跑出来的结果等于没写。三态怎么分见本命令正文里「跑 check 命令:退出码的三态语义」一节;正文里没有这一节的命令不跑 check 命令,checks写{}。⚠️ 没有检查命令可跑的阶段(如 requirements/design 只产文档,或项目无
test-commands.yml)→checks: {}留空。绝不因为「本阶段成功」就把tests_pass/lint_clean等填true——那是虚报,会污染跨工具共用的状态机、误导自主循环判停。 上面 schema 示例里checks之所以是空的,正是这个原因——空是"没跑"的意思,不是键名的示范。self_audit单列:只放自检未通过数,仅供参考,不作循环判停依据。ok的定义:本阶段全部checks通过且未命中blocked_reason→true;否则false。命名空间:
advanced_to= 下一阶段的短名,不是命令名、也不是本阶段的current_stage。三者关系:stage=本阶段短名、current_stage=本阶段完成后的当前短名、advanced_to=下一阶段短名、next_step=下一跳命令名。⛔ 短名不是「命令名去掉
pdlc-前缀」——pdlc-implement的短名是impl,不是implement。别推导,查下表:
next_step(下一跳命令名) |
advanced_to(下一阶段短名) |
|---|---|
pdlc-tdd |
tdd |
pdlc-implement |
impl |
pdlc-review |
review |
pdlc-design |
design |
pdlc-ship |
ship |
pdlc-deploy |
deploy |
next_step 为 null(终态或无后续)时 advanced_to 也是 null。
📌 本表是唯一真源,且是被断言钉住的:每行的短名必须等于该 skill 自己 frontmatter 里声明的
stage:,且任何 skill 的非nullnext_step都必须在表里有行——两个方向 都由tests/frontmatter-check.sh检查,所以表不会和实现各自漂移。写错短名的后果与键名写错同类:消费方按契约名匹配,认不出就当没这个阶段。
- 推进一致:
ok=true时本阶段必须真的推进了current_stage(与第 6 条 IRON LAW 呼应);到达终态或无后续时advanced_to=null。ok=false(含 blocked)时current_stage不变、advanced_to=null、blocked_reason写明原因。 run_mode:镜像本次调用是否带--autonomous(带了写autonomous,没带写interactive)。
段四:交接(Handoff)
命令完成后必须输出以下格式的最终消息:
✅ <阶段名> 完成:<主要产出物路径>
📊 自检:<通过数>/<总数> 通过(若有未通过,附要点)
📦 状态快照:docs/.pdlc-state/<feature-id>.json
👉 下一步:/pdlc-<next_step>
(如果有分叉)或 /pdlc-<alt>(条件:<选择依据>)
规则:
- 主流程命令(写状态机的命令;下一跳见正文里「本命令的状态机取值」)必须显式输出"下一步",不可省略
- 工具型命令(Layer 3)可以没有
next_step,此时输出👉 下一步:(本次流程结束,无后续) - 分叉场景必须说明选择条件,例如"若需补充测试用例 →
/pdlc-tdd;若测试已齐 →/pdlc-review"
Files (pdlc-skills)
-
assets
-
api-design-template.md 10 KB
# API 设计文档:[模块名称] > 关联需求:REQ-YYYYMM-XXX > 创建日期: > 作者: > 评审人: > 状态:草稿 | 已评审 | 已批准 > 版本:v1.0 --- ## 1. 概述 简要说明本模块提供的 API 能力、使用场景和接入方。 | 项目 | 说明 | |------|------| | 基础路径 | `/api/v1/[模块名]` | | 生产环境 | `https://api.example.com` | | 测试环境 | `https://api-staging.example.com` | | 认证方式 | Bearer Token(JWT) | | 数据格式 | JSON(`Content-Type: application/json`) | | 字符编码 | UTF-8 | | 接口数量 | N 个 | --- ## 2. 接口总览 | 方法 | 路径 | 描述 | 需求编号 | 权限 | 状态 | |------|------|------|----------|------|------| | POST | `/api/v1/orders` | 创建订单 | REQ-202603-001 | 已登录用户 | 待开发 | | GET | `/api/v1/orders/{orderId}` | 查询订单详情 | REQ-202603-002 | 已登录用户 | 待开发 | | GET | `/api/v1/orders` | 查询订单列表 | REQ-202603-003 | 已登录用户 | 待开发 | | PUT | `/api/v1/orders/{orderId}/cancel` | 取消订单 | REQ-202603-004 | 已登录用户 | 待开发 | --- ## 3. 通用约定 ### 3.1 请求头 | Header | 必填 | 说明 | |--------|------|------| | `Authorization` | 是 | `Bearer <token>` | | `Content-Type` | 是(有 Body 时) | `application/json` | | `X-Request-Id` | 否 | 调用方传入的请求唯一标识,用于链路追踪 | | `X-Idempotency-Key` | 是(写接口) | 幂等键,防止重复提交,建议使用 UUID | ### 3.2 统一响应结构 ```json { "code": 0, "message": "success", "data": {}, "requestId": "abc-123", "timestamp": 1711382400000 } ``` | 字段 | 类型 | 说明 | |------|------|------| | `code` | int | 业务状态码,0 表示成功 | | `message` | string | 提示信息 | | `data` | object / array / null | 响应数据 | | `requestId` | string | 请求唯一标识 | | `timestamp` | long | 服务器时间戳(毫秒) | ### 3.3 分页结构 列表接口统一使用以下分页参数和响应结构: **请求参数:** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | `page` | int | 否 | 1 | 页码,从 1 开始 | | `pageSize` | int | 否 | 20 | 每页数量,最大 100 | **响应 `data` 结构:** ```json { "list": [], "total": 100, "page": 1, "pageSize": 20, "totalPages": 5 } ``` ### 3.4 错误码定义 | code | HTTP 状态码 | 含义 | 说明 | |------|------------|------|------| | 0 | 200 | 成功 | - | | 10001 | 400 | 参数错误 | 请求参数校验失败 | | 10002 | 401 | 未认证 | Token 缺失或已过期 | | 10003 | 403 | 无权限 | 无操作权限 | | 10004 | 404 | 资源不存在 | - | | 10005 | 409 | 资源冲突 | 如重复提交 | | 10006 | 429 | 请求过于频繁 | 触发限流 | | 50000 | 500 | 服务器内部错误 | - | | 50001 | 503 | 服务不可用 | 依赖服务故障 | > 业务模块错误码在模块内自定义,格式建议:`模块码(3位)+ 错误序号(3位)`,如订单模块 `201001`。 --- ## 4. 接口详情 ### 4.1 创建订单 **需求编号**:REQ-202603-001 ``` POST /api/v1/orders ``` **描述**:用户提交订单,系统创建订单并返回订单编号。 **权限**:已登录用户 **请求参数:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | `addressId` | long | 是 | 收货地址 ID | | `items` | array | 是 | 商品列表 | | `items[].productId` | long | 是 | 商品 ID | | `items[].quantity` | int | 是 | 购买数量,最小值 1 | | `remark` | string | 否 | 订单备注,最大 500 字符 | **请求示例:** ```json { "addressId": 10086, "items": [ { "productId": 1001, "quantity": 2 }, { "productId": 1002, "quantity": 1 } ], "remark": "尽快发货" } ``` **响应参数:** | 参数 | 类型 | 说明 | |------|------|------| | `orderId` | long | 订单 ID | | `orderNo` | string | 订单编号 | | `totalAmount` | int | 订单总金额(分) | | `status` | int | 订单状态(0=待支付) | | `createdAt` | string | 创建时间(ISO 8601) | **响应示例:** ```json { "code": 0, "message": "success", "data": { "orderId": 88888, "orderNo": "ORD20260318000001", "totalAmount": 19900, "status": 0, "createdAt": "2026-03-18T10:00:00+08:00" }, "requestId": "abc-123", "timestamp": 1742266800000 } ``` **错误码:** | code | 说明 | |------|------| | 10001 | 参数校验失败(如 quantity < 1) | | 201001 | 商品不存在或已下架 | | 201002 | 库存不足 | | 201003 | 收货地址不存在 | --- ### 4.2 查询订单详情 **需求编号**:REQ-202603-002 ``` GET /api/v1/orders/{orderId} ``` **描述**:根据订单 ID 查询订单详情,仅允许查询本人订单。 **权限**:已登录用户 **路径参数:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | `orderId` | long | 是 | 订单 ID | **响应参数:** | 参数 | 类型 | 说明 | |------|------|------| | `orderId` | long | 订单 ID | | `orderNo` | string | 订单编号 | | `status` | int | 订单状态(见枚举) | | `totalAmount` | int | 订单总金额(分) | | `payAmount` | int | 实付金额(分) | | `items` | array | 商品列表 | | `items[].productId` | long | 商品 ID | | `items[].productName` | string | 商品名称 | | `items[].quantity` | int | 数量 | | `items[].unitPrice` | int | 单价(分) | | `createdAt` | string | 创建时间 | | `paidAt` | string / null | 支付时间 | **订单状态枚举:** | 值 | 含义 | |----|------| | 0 | 待支付 | | 1 | 已支付 | | 2 | 已发货 | | 3 | 已完成 | | 9 | 已取消 | **响应示例:** ```json { "code": 0, "message": "success", "data": { "orderId": 88888, "orderNo": "ORD20260318000001", "status": 0, "totalAmount": 19900, "payAmount": 19900, "items": [ { "productId": 1001, "productName": "示例商品 A", "quantity": 2, "unitPrice": 9000 }, { "productId": 1002, "productName": "示例商品 B", "quantity": 1, "unitPrice": 1900 } ], "createdAt": "2026-03-18T10:00:00+08:00", "paidAt": null }, "requestId": "abc-124", "timestamp": 1742266900000 } ``` **错误码:** | code | 说明 | |------|------| | 10003 | 无权限(非本人订单) | | 10004 | 订单不存在 | --- ### 4.3 查询订单列表 **需求编号**:REQ-202603-003 ``` GET /api/v1/orders ``` **描述**:分页查询当前用户的订单列表,支持按状态筛选。 **权限**:已登录用户 **Query 参数:** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | `status` | int | 否 | - | 订单状态筛选,不传则查询全部 | | `page` | int | 否 | 1 | 页码 | | `pageSize` | int | 否 | 20 | 每页数量 | **响应参数(`data.list[]` 单条字段):** | 参数 | 类型 | 说明 | |------|------|------| | `orderId` | long | 订单 ID | | `orderNo` | string | 订单编号 | | `status` | int | 订单状态(见枚举) | | `totalAmount` | int | 订单总金额(分) | | `createdAt` | string | 创建时间 | **响应示例:** ```json { "code": 0, "message": "success", "data": { "list": [ { "orderId": 88888, "orderNo": "ORD20260318000001", "status": 0, "totalAmount": 19900, "createdAt": "2026-03-18T10:00:00+08:00" } ], "total": 1, "page": 1, "pageSize": 20, "totalPages": 1 }, "requestId": "abc-125", "timestamp": 1742267000000 } ``` --- ### 4.4 取消订单 **需求编号**:REQ-202603-004 ``` PUT /api/v1/orders/{orderId}/cancel ``` **描述**:取消待支付状态的订单,其他状态不允许取消。 **权限**:已登录用户 **路径参数:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | `orderId` | long | 是 | 订单 ID | **请求参数:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | `reason` | string | 否 | 取消原因,最大 200 字符 | **请求示例:** ```json { "reason": "不想买了" } ``` **响应示例:** ```json { "code": 0, "message": "success", "data": null, "requestId": "abc-126", "timestamp": 1742267100000 } ``` **错误码:** | code | 说明 | |------|------| | 10003 | 无权限(非本人订单) | | 10004 | 订单不存在 | | 201004 | 订单状态不允许取消(非待支付状态) | --- ## 5. 数据模型 ### 5.1 OrderVO(订单视图对象) | 字段 | 类型 | 说明 | |------|------|------| | `orderId` | long | 订单 ID | | `orderNo` | string | 订单编号 | | `status` | int | 订单状态 | | `totalAmount` | int | 订单总金额(分) | | `payAmount` | int | 实付金额(分) | | `remark` | string | 备注 | | `createdAt` | string | 创建时间(ISO 8601) | | `paidAt` | string / null | 支付时间 | | `items` | array\<OrderItemVO\> | 商品明细 | ### 5.2 OrderItemVO(订单明细视图对象) | 字段 | 类型 | 说明 | |------|------|------| | `productId` | long | 商品 ID | | `productName` | string | 商品名称 | | `quantity` | int | 数量 | | `unitPrice` | int | 单价(分) | | `subtotal` | int | 小计(分) | --- ## 6. 限流与安全 | 接口 | 限流规则 | 说明 | |------|----------|------| | POST `/api/v1/orders` | 10次/分钟/用户 | 防止重复提交 | | GET `/api/v1/orders` | 60次/分钟/用户 | 正常查询 | | PUT `.../cancel` | 5次/分钟/用户 | 防止频繁操作 | - 所有写接口需携带幂等键(`X-Idempotency-Key`),服务端保证相同 key 重复请求只处理一次 - 敏感字段(如金额)在日志中脱敏处理 --- ## 7. 变更记录 | 版本 | 日期 | 变更内容 | 作者 | |------|------|----------|------| | v1.0 | | 初始版本 | | --- ## 8. 评审记录 | 日期 | 评审人 | 问题 | 处理结果 | |------|--------|------|----------| --- **关联文档:** - 需求文档:`docs/01_requirements/prd/` - 数据库设计:`docs/02_design/database/` - 架构设计:`docs/02_design/architecture/`
-
-
SKILL.md 17.2 KB
--- name: pdlc-design description: 创建技术设计文档(自动生成 + 自检 + handoff) argument-hint: <功能ID | 功能描述> allowed-tools: Read, Write, Edit, Glob, Grep, Bash layer: 2 stage: design produces: - docs/02_design/<subsystem>/<feature-id>-design.md requires: - docs/01_requirements/prd/ next_step: pdlc-tdd terminal_state: design_done --- # 创建设计文档 <!-- @include templates/prompts/iron-law.md(已内联于下方,无需另读) --> ⛔ **IRON LAW · 不可违反的硬门禁** 以下规则为**不可协商**的执行约束: 1. **文件必须落盘**:所有带编号(功能ID / 缺陷ID)的文档,必须作为实际文件写入磁盘,不可仅在对话中输出。 2. **阶段必须落章**:每个阶段完成后必须在状态机 `docs/.pdlc-state/<feature-id>.json` 追加 history,不可跳过。 3. **测试必须存在**:进入 `/pdlc-implement` 前,对应测试必须存在且处于红灯状态。违反则中止。 4. **自检必须执行**:段二自检为强制步骤,不得以"已经很好了"为由跳过。 5. **防循环**:段三修复为单次,不递归。无法自动修复的问题记录到报告,继续往下走。 6. **状态必推进**:成功执行某 phase 后 `current_stage` 必须变更。收尾时若发现 `current_stage` 未推进,视为失败并报错,**不得静默返回**(防止外层循环拿滞后的状态空转烧额度)。唯一例外:命中人工点主动 block 时,`current_stage` 保持不变但必须写 `last_phase_result.ok=false` + `blocked_reason`。 **违反任一条 = 立即中止当前命令,输出违规详情,等待人工介入。** <!-- @include-end templates/prompts/iron-law.md --> 根据已有的需求文档,在 `docs/02_design/` 对应子目录下创建技术设计文档。 ## 输入解析 从本命令的参数中判断输入类型: - **文件路径**(以 `/`、`./` 开头,或以 `.md`、`.txt`、`.pdf` 结尾,或实际存在的文件):直接读取该文件作为需求来源,跳过 PRD 搜索 - **功能名关键词**(默认):按下方守卫检查搜索 PRD ## PDLC 前置检查(必须执行,不可跳过) 1. 若输入为文件路径,直接读取文件内容作为需求,提取功能名和功能ID(如有),跳到步骤 4 2. 从用户输入中提取功能名称关键词 3. 在 `docs/01_requirements/prd/` 目录下搜索包含该关键词的 PRD 文档 - 匹配新格式:`F<日期>-<编号>-*<关键词>*-prd.md` - 匹配旧格式:`YYYYMMDD-*<关键词>*-prd.md` - 同时检查文件内容中是否包含该关键词 3. **未找到** → 输出以下信息后**立即停止,不继续执行**: ``` ⛔ PDLC 守卫:未找到与「<功能名>」相关的 PRD 文档。 设计文档必须基于已有的 PRD。请先运行: 👉 /pdlc-prd <需求描述> ``` 4. **找到** → 提取功能ID(如 `F20260326-090000`),读取该 PRD 内容,继续执行 ## 输出位置 - API 设计 → `docs/02_design/api/` - 架构设计 → `docs/02_design/architecture/` - 数据库设计 → `docs/02_design/database/` ## 要求 1. 先阅读找到的 PRD 文档,全面理解需求 2. 参考 本 skill 目录下的 `assets/api-design-template.md` 获取 API 设计模板格式 3. 参考 `docs/00_standards/` 目录了解项目规范(未命中 → 提示 `consider /pdlc-standard add <category>/<topic>`) 4. **文件名格式**: `<功能ID>-<功能名>-<类型>.md`(如 `F20260326-090000-user-auth-api.md`),类型可以是 api / arch / db - 若 PRD 为旧格式无功能ID,则使用旧格式 `YYYYMMDD-<功能名>-<类型>.md` 5. **文档顶部必须包含 PDLC 追溯头**: ``` <!-- PDLC-TRACE --> <!-- 功能ID: F20260326-090000 --> <!-- 功能名称: user-auth --> <!-- 阶段: 设计 --> <!-- 前置文档: docs/01_requirements/prd/F20260326-090000-user-auth-prd.md --> ``` <!-- @include templates/prompts/output-language.md(已内联于下方,无需另读) --> 🌐 **Output language for generated artifacts** All generated artifacts (PRDs, design docs, code comments, review reports, test plans, deployment manuals, changelog entries, etc.) follow this policy: 1. **Default — match the conversation language exactly**: - 用户用中文与 Claude 对话 → 产中文文档、中文代码注释、中文报告 - User talks to Claude in English → produce English artifacts - User talks in another language → produce artifacts in that language - **Never silently default to a fixed language regardless of the user's input.** 2. **Explicit override always wins**: when the user specifies a language for an artifact (e.g. "write the PRD in English", "用英文写 API 设计文档", "output the deploy doc in Japanese"), use that language for that artifact, regardless of conversation language. 3. **Mixed-language requirements**: if the user wants some artifacts in one language and others in a different language (common: Chinese PRD + English API docs for partners), honour each per-artifact instruction. 4. **Uncertain**: if you cannot reliably detect the conversation language, ask once before producing the first artifact. This policy applies to **content** (prose, comments, headings). It does **not** override technical conventions like English variable names, English git commit subjects, or English error codes when the project's conventions require them. <!-- @include-end templates/prompts/output-language.md --> 7. 必须包含:概述、接口/架构/表结构定义、错误码/异常处理、数据模型 8. API 设计需遵循 RESTful 规范,统一响应格式 `{ code, message, data }` 9. **设计文档自审与自动修复**(每份设计文档创建后立即执行,不可跳过): - 重新阅读刚创建的设计文档,对照 PRD 逐项检查以下质量门禁: **PRD 一致性检查**: - [ ] PRD 中每条 P0/P1 功能是否都有对应的设计覆盖(接口/表结构/架构组件) - [ ] 接口的入参/出参是否与 PRD 描述的功能行为一致 - [ ] 错误码是否覆盖了 PRD 中列出的异常场景 **API 设计检查**(如有 API 文档): - [ ] 接口 URL 命名是否遵循 RESTful 规范(名词复数、层级清晰) - [ ] 请求/响应结构是否完整(无缺失字段) - [ ] 统一响应格式 `{ code, message, data }` 是否一致执行 - [ ] 分页接口是否有 page/pageSize/total 参数 - [ ] 鉴权方式是否明确说明 **数据库设计检查**(如有 DB 文档): - [ ] 每张表是否有主键定义 - [ ] 外键关系是否与 ER 图一致 - [ ] 常用查询字段是否有索引设计 - [ ] 是否有 `created_at`、`updated_at` 等审计字段 - [ ] 迁移 DDL 是否完整可执行 **跨文档一致性检查**(如同时有 API + DB 文档): - [ ] API 响应字段是否与数据库字段对应(字段名、类型) - [ ] API 的查询/筛选参数是否有对应的数据库索引支撑 **自动修复**: - PRD 功能遗漏:自动补充对应的接口/表设计 - 缺失的错误码:根据接口行为自动补充常见错误码(400/401/403/404/409/500) - 缺失的索引:根据查询模式自动补充索引设计 - 缺失的审计字段:自动添加 `created_at`、`updated_at` - 缺失的分页参数:自动补充列表接口的分页设计 - 修复后在文档末尾追加审查记录: ``` ## 自审记录 - 审查时间:<ISO 8601> - 对照 PRD:<PRD 文件路径> - 发现问题:X 项 - 自动修复:X 项 - 修复明细: - [已修复] <问题描述> ``` 10. 创建完成后,提示用户下一步是编写测试用例(`/pdlc-tdd <功能名>`) 设计目标: $ARGUMENTS <!-- pdlc:meta 由 frontmatter 生成(adapters/sync_skills.py),勿手改 --> > **本命令的状态机取值**:阶段短名 `design`(写进 `history[].stage` 与 `last_phase_result.stage`);下一跳 `pdlc-tdd`(写进 `next_step`,交接时提示)。 <!-- pdlc:meta-end --> <!-- @include templates/prompts/state-update.md(已内联于下方,无需另读) --> ## 状态机更新(段四必须执行) 本命令完成主产出后,必须更新状态机文件 `docs/.pdlc-state/<feature-id>.json`。 ### 文件格式 ```json { "feature_id": "<F/B ID>", "feature_name": "<kebab-case>", "created_at": "<首次创建时间 ISO 8601>", "current_stage": "<当前阶段名>", "run_mode": "interactive | autonomous", "history": [ { "stage": "<阶段名>", "done_at": "<ISO 8601>", "produced": ["<相对路径 1>", "<相对路径 2>"], "self_audit": { "passed": <N>, "failed": <N>, "manual": <N> }, "auto_decisions": [ { "point": "<autonomous 下自动前进的确认点>", "chose": "<所选默认>", "at": "<ISO 8601>" } ] } ], "last_phase_result": { "stage": "<本次阶段名>", "ok": true, "advanced_to": "<推进到的下一阶段 | null>", "checks": {}, "self_audit": { "failed": 0 }, "blocked_reason": null, "run_mode": "interactive | autonomous", "at": "<ISO 8601>" }, "relations": { "extends": [], "depends_on": [], "supersedes": [], "resolves": [], "conflicts_with": [], "relates_to": [], "_updated_at": "<ISO 8601 | 省略>" }, "next_step": "<下一跳命令名,如 pdlc-design;若流程结束则为 null>" } ``` > ⛔ 示例里的 `"checks": {}` 是「本阶段没有命令可跑」的样子,**不是键名示范**——键名与取值见下方 §1。 > **`relations` 块(RFC#6,Phase 1 可选,Phase 2 推荐)**:6 个 key 对应 6 种关系类型,各为 ID 数组,存**出边**。其中 `conflicts_with` / `relates_to` 是对称类型,两端都要写;其余四种有向,只写在源 feature 上。拿不准时用 `/pdlc-relate set` 写入,它会按规则校验。旧状态文件无此块时视为全空,向后兼容。入边由 `/pdlc-relate rebuild` 派生到 `_relations.json`,不在此块手维护。 > ⛔ **写状态机的四条硬约束**——读侧(`/pdlc-status`、`/pdlc-retro`、`/pdlc-relate`)会逐条体检, > 违反的每一处都会出现在它们输出的最前面: > > 1. **实例里不写 `terminal_state`**。skill frontmatter 的 `terminal_state:` 是「这个命令走完后应到达的终态名」, > 不是状态字段。判终态只看 `current_stage` 是否以 `_done` 结尾。 > 2. **`history[].stage` 写本命令的阶段短名**(见本命令正文里「本命令的状态机取值」)——`pdlc-implement` 写 `impl`, > 不写 `implement` / `implementation`;`pdlc-prd` 写 `requirements`,不写 `prd`。 > 3. **时间戳必须带时刻**:`created_at` / `done_at` / `at` 一律写完整 ISO 8601(如 `2026-07-28T10:40:00+08:00`)。 > 只写日期,同一天内的阶段耗时就全部算成 0——读侧只能记「不可测」。 > 4. **`next_step` 只写命令名或 `null`**,不附说明文字(如「pdlc-ship(等评审通过)」)。 > 要说明原因,阻塞时写进 `last_phase_result.blocked_reason`。 > ⛔ **`_done` 的含义是「已发布」,只由 `/pdlc-ship`(写 `ship_done`)与 `/pdlc-deploy`(写 `deploy_done`)写入。** > 其它命令的 `current_stage` 一律写本命令的阶段短名,走完整条链路的编排命令(`/pdlc-feature`)也一样—— > 它收尾时 `current_stage` 是最后一个阶段的短名,`next_step` 是 `pdlc-ship`。 > > - 「评审通过、等待发布」就是 `current_stage` 为 `review`(或 `e2e` 等)且 `next_step` 为 `pdlc-ship`。 > 循环相关文档里说的 `review_done` 指的就是这个状态,**不是**要写进 `current_stage` 的值。 > - 为什么:读侧判「已抵达终态」只看 `current_stage` 是否以 `_done` 结尾。评审通过就写 `_done`, > `/pdlc-ship` 就分不清哪些功能已经发布过,发布说明会重复或漏收。 > - 旧版本写入的 `feature_done` / `fix_done` / `review_done` 分不清是否已发布,`/pdlc-ship` 会列出来请人确认。 ### 更新流程 1. **文件不存在** → 创建文件,写入初始结构(`history` 为含当前阶段的数组) 2. **文件存在** → 读取 JSON,追加当前阶段到 `history`,更新 `current_stage` 和 `next_step` 3. **写回文件**:用 `jq` 或等效工具保持格式化 ⚠️ 若更新失败(文件损坏/权限问题),必须中止命令并在最终报告中报错。状态机不可跳过。 ### `last_phase_result`(机器可读阶段结果,每个 phase 收尾必写) 顶层 `last_phase_result` 是循环判停的**唯一真源**,外层只需 `jq '.last_phase_result.ok'` 即可决定 继续 / 停止 / 交还人类。规则: 1. **`checks` 必须客观、真跑得来**:只放**真跑命令的退出码**结果(命令取自 `docs/00_standards/test-commands.yml`,见 `test-commands-template.yml`),**绝不用模型自评、绝不填占位**。有测试的阶段用 `tests_pass` / `coverage_pass` / `lint_clean`(退出码 0 → `true`,非 0 → `false`);stage 语义不同用对应键(如 tdd 段 `{ "red_verified": true }` 表示红灯已验证)。 > ⛔ **键名与类型都是契约的一部分**:键名只能是 `tests_pass` / `coverage_pass` / > `lint_clean` / `e2e_pass`(tdd 段 `red_verified`),值只能是**布尔**。 > 最常见的两种错法:① 照抄 `test-commands.yml` 的 `unit` / `coverage` / `lint` / `e2e` > ——那是**命令表**的字段名,不是状态机的(跑 `unit` 得到的结论写进 `tests_pass`); > ② 写成 `"4 passed, 1 failed"` 这类字符串摘要。两种都会让 `jq '.checks.tests_pass'` > 读回 `null`,消费方(发布闸门、质量报告、自主循环)只看到「无法判定」—— > **你诚实跑出来的结果等于没写**。三态怎么分见本命令正文里「跑 check 命令:退出码的三态语义」一节;正文里没有这一节的命令不跑 check 命令,`checks` 写 `{}`。 > > ⚠️ **没有检查命令可跑的阶段(如 requirements/design 只产文档,或项目无 `test-commands.yml`)→ `checks: {}` 留空。绝不因为「本阶段成功」就把 `tests_pass`/`lint_clean` 等填 `true`——那是虚报,会污染跨工具共用的状态机、误导自主循环判停。** 上面 schema 示例里 `checks` 之所以是空的,正是这个原因——**空是"没跑"的意思,不是键名的示范**。 2. **`self_audit` 单列**:只放自检未通过数,**仅供参考,不作循环判停依据**。 3. **`ok` 的定义**:本阶段全部 `checks` 通过且未命中 `blocked_reason` → `true`;否则 `false`。 4. **命名空间**:`advanced_to` = **下一阶段的短名**,**不是命令名、也不是本阶段的 `current_stage`**。三者关系:`stage`=本阶段短名、`current_stage`=本阶段完成后的当前短名、`advanced_to`=下一阶段短名、`next_step`=下一跳命令名。 ⛔ **短名不是「命令名去掉 `pdlc-` 前缀」**——`pdlc-implement` 的短名是 **`impl`**,不是 `implement`。别推导,查下表: <!-- stage-map:start --> | `next_step`(下一跳命令名) | `advanced_to`(下一阶段短名) | |---|---| | `pdlc-tdd` | `tdd` | | `pdlc-implement` | `impl` | | `pdlc-review` | `review` | | `pdlc-design` | `design` | | `pdlc-ship` | `ship` | | `pdlc-deploy` | `deploy` | <!-- stage-map:end --> `next_step` 为 `null`(终态或无后续)时 `advanced_to` 也是 `null`。 > 📌 **本表是唯一真源,且是被断言钉住的**:每行的短名必须等于该 skill 自己 frontmatter > 里声明的 `stage:`,且任何 skill 的非 `null` `next_step` 都必须在表里有行——两个方向 > 都由 `tests/frontmatter-check.sh` 检查,所以表不会和实现各自漂移。 > > 写错短名的后果与键名写错同类:消费方按契约名匹配,认不出就当没这个阶段。 5. **推进一致**:`ok=true` 时本阶段必须真的推进了 `current_stage`(与第 6 条 IRON LAW 呼应);到达终态或无后续时 `advanced_to=null`。`ok=false`(含 blocked)时 `current_stage` 不变、`advanced_to=null`、`blocked_reason` 写明原因。 6. **`run_mode`**:镜像本次调用是否带 `--autonomous`(带了写 `autonomous`,没带写 `interactive`)。 <!-- @include-end templates/prompts/state-update.md --> <!-- @include templates/prompts/handoff.md(已内联于下方,无需另读) --> ## 段四:交接(Handoff) 命令完成后必须输出以下格式的最终消息: ``` ✅ <阶段名> 完成:<主要产出物路径> 📊 自检:<通过数>/<总数> 通过(若有未通过,附要点) 📦 状态快照:docs/.pdlc-state/<feature-id>.json 👉 下一步:/pdlc-<next_step> (如果有分叉)或 /pdlc-<alt>(条件:<选择依据>) ``` **规则:** - 主流程命令(写状态机的命令;下一跳见正文里「本命令的状态机取值」)必须显式输出"下一步",不可省略 - 工具型命令(Layer 3)可以没有 `next_step`,此时输出 `👉 下一步:(本次流程结束,无后续)` - 分叉场景必须说明**选择条件**,例如"若需补充测试用例 → `/pdlc-tdd`;若测试已齐 → `/pdlc-review`" <!-- @include-end templates/prompts/handoff.md -->
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.