基于 OpenClaw + Claude Code 的端到端研发自动化系统任务拆解
从需求→PRD 设计→技术方案→API 开发→AI Coding→测试→CI/CD 自动部署全流程
核心职责:
使用工具: OpenClaw + MCP(Jira/Notion) + Claude Code
输出产物: PRD 文档、用户故事、原型图描述
核心职责:
使用工具: Claude Code + MCP(GitHub/DB) + Swagger
输出产物: 技术方案、API 规范、源代码、单元测试
核心职责:
使用工具: Claude Code + MCP(Figma) + Storybook
输出产物: 前端源码、组件文档、E2E 测试
核心职责:
使用工具: Jest/Pytest + Selenium + SonarQube
输出产物: 测试报告、覆盖率报告、Bug 列表
核心职责:
使用工具: Jenkins + Docker + KubeSphere + Prometheus
输出产物: CI/CD 脚本、部署手册、监控大盘
| 规范项 | 正确示例 | 错误示例 | 说明 |
|---|---|---|---|
| 使用名词复数 | /api/v1/users |
/api/v1/user |
集合资源使用复数形式 |
| 避免动词 | POST /users |
GET /createUser |
HTTP 方法表达操作 |
| 小写字母 + 连字符 | /user-profiles |
/userProfiles |
URL 统一小写,单词用 - 分隔 |
| 嵌套资源不超过 3 层 | /users/{id}/posts |
/users/{id}/posts/{pid}/comments |
过深嵌套降低可读性 |
| 版本号在路径中 | /api/v1/resources |
/api/resources?v=1 |
便于版本管理和缓存 |
| 方法 | 幂等性 | 用途 | 成功响应码 |
|---|---|---|---|
GET |
是 | 获取资源 (只读) | 200 OK |
POST |
否 | 创建资源 | 201 Created |
PUT |
是 | 全量更新资源 | 200 OK / 204 No Content |
PATCH |
否 | 部分更新资源 | 200 OK |
DELETE |
是 | 删除资源 | 204 No Content |
{
"error": {
"code": "VALIDATION_ERROR",
"message": "请求参数验证失败",
"details": [
{
"field": "email",
"message": "邮箱格式不正确"
},
{
"field": "password",
"message": "密码长度至少 8 位"
}
],
"timestamp": "2026-03-14T10:30:00Z",
"path": "/api/v1/users",
"requestId": "req_abc123xyz"
}
}
# 分页
GET /api/v1/users?page=1&size=20
# 排序
GET /api/v1/users?sort=createdAt,desc
# 过滤
GET /api/v1/users?status=active&role=admin
# 字段选择
GET /api/v1/users?fields=id,name,email
# 组合使用
GET /api/v1/users?page=1&size=10&status=active&sort=name,asc&fields=id,name
# Queries (查询操作)
type Query {
# 单个资源
user(id: ID!): User
post(slug: String!): Post
# 资源列表 (带分页)
users(first: Int, after: String): UserConnection!
posts(filter: PostFilter, first: Int, after: String): PostConnection!
# 搜索
searchUsers(query: String!, first: Int): UserConnection!
}
# Mutations (变更操作)
type Mutation {
# 创建
createUser(input: CreateUserInput!): CreateUserPayload!
updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
# 删除
deleteUser(id: ID!): DeleteUserPayload!
# 批量操作
bulkUpdateUsers(ids: [ID!]!, input: UpdateUserInput!): [User]!
}
# Connection 模式
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type UserEdge {
node: User!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
# 查询示例
query {
users(first: 10, after: "Y3Vyc29yOjEw") {
edges {
node {
id
name
email
}
cursor
}
pageInfo {
hasNextPage
endCursor
}
totalCount
}
}
# Union 类型处理错误
union UserResult = User | UserError
type UserError {
code: ErrorCode!
message: String!
field: String
}
enum ErrorCode {
NOT_FOUND
VALIDATION_ERROR
UNAUTHORIZED
CONFLICT
}
# 或者使用标准 GraphQL 错误 + extensions
{
"errors": [
{
"message": "邮箱已被注册",
"locations": [{"line": 2, "column": 3}],
"path": ["createUser"],
"extensions": {
"code": "VALIDATION_ERROR",
"field": "email",
"timestamp": "2026-03-14T10:30:00Z"
}
}
]
}
openapi: 3.0.3
info:
title: 用户管理系统 API
description: |
基于 OpenClaw + Claude Code 自动化生成的用户管理系统 RESTful API
## 认证方式
所有接口需要使用 JWT Token 认证,在 Header 中添加:
```
Authorization: Bearer <your_token>
```
## 速率限制
- 普通用户:100 次/分钟
- VIP 用户:500 次/分钟
version: 1.0.0
contact:
name: API Support
email: api-support@example.com
license:
name: MIT
url: https://opensource.org/licenses/MIT
servers:
- url: https://api.example.com/v1
description: 生产环境
- url: https://staging-api.example.com/v1
description: 预发布环境
- url: http://localhost:8080/v1
description: 本地开发环境
tags:
- name: Users
description: 用户管理相关接口
- name: Authentication
description: 认证授权相关接口
paths:
/users:
get:
tags:
- Users
summary: 获取用户列表
description: 支持分页、过滤、排序的用户列表查询
operationId: listUsers
parameters:
- name: page
in: query
description: 页码 (从 1 开始)
schema:
type: integer
default: 1
minimum: 1
- name: size
in: query
description: 每页数量
schema:
type: integer
default: 20
minimum: 1
maximum: 100
- name: status
in: query
description: 用户状态过滤
schema:
type: string
enum: [active, inactive, banned]
- name: sort
in: query
description: 排序字段
schema:
type: string
default: createdAt,desc
responses:
'200':
description: 成功返回用户列表
content:
application/json:
schema:
$ref: '#/components/schemas/UserListResponse'
'401':
description: 未授权
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
security:
- bearerAuth: []
post:
tags:
- Users
summary: 创建新用户
operationId: createUser
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
responses:
'201':
description: 用户创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/User'
headers:
Location:
description: 新创建资源的 URL
schema:
type: string
format: uri
'400':
description: 请求参数错误
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
'409':
description: 邮箱已存在
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
security:
- bearerAuth: []
/users/{userId}:
get:
tags:
- Users
summary: 获取单个用户详情
operationId: getUserById
parameters:
- name: userId
in: path
required: true
description: 用户 ID
schema:
type: string
format: uuid
responses:
'200':
description: 成功返回用户详情
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
description: 用户不存在
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
security:
- bearerAuth: []
put:
tags:
- Users
summary: 全量更新用户
operationId: updateUser
parameters:
- name: userId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateUserRequest'
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/User'
security:
- bearerAuth: []
delete:
tags:
- Users
summary: 删除用户
operationId: deleteUser
parameters:
- name: userId
in: path
required: true
schema:
type: string
format: uuid
responses:
'204':
description: 删除成功
'404':
description: 用户不存在
security:
- bearerAuth: []
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
User:
type: object
required:
- id
- email
- username
- status
- createdAt
properties:
id:
type: string
format: uuid
example: "550e8400-e29b-41d4-a716-446655440000"
email:
type: string
format: email
example: "user@example.com"
username:
type: string
minLength: 3
maxLength: 50
example: "john_doe"
status:
type: string
enum: [active, inactive, banned]
example: "active"
role:
type: string
enum: [user, admin, super_admin]
default: "user"
profile:
$ref: '#/components/schemas/UserProfile'
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
UserProfile:
type: object
properties:
firstName:
type: string
example: "John"
lastName:
type: string
example: "Doe"
avatar:
type: string
format: uri
bio:
type: string
maxLength: 500
CreateUserRequest:
type: object
required:
- email
- password
- username
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
writeOnly: true
username:
type: string
minLength: 3
maxLength: 50
profile:
$ref: '#/components/schemas/UserProfile'
UpdateUserRequest:
type: object
properties:
email:
type: string
format: email
username:
type: string
minLength: 3
maxLength: 50
status:
type: string
enum: [active, inactive, banned]
profile:
$ref: '#/components/schemas/UserProfile'
UserListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
pagination:
$ref: '#/components/schemas/PaginationInfo'
PaginationInfo:
type: object
properties:
page:
type: integer
size:
type: integer
totalItems:
type: integer
totalPages:
type: integer
hasNext:
type: boolean
hasPrev:
type: boolean
Error:
type: object
required:
- code
- message
- timestamp
properties:
code:
type: string
example: "USER_NOT_FOUND"
message:
type: string
example: "用户不存在"
details:
type: array
items:
type: object
properties:
field:
type: string
message:
type: string
timestamp:
type: string
format: date-time
requestId:
type: string
example: "req_abc123"
ValidationError:
allOf:
- $ref: '#/components/schemas/Error'
- type: object
properties:
errors:
type: array
items:
type: object
properties:
field:
type: string
message:
type: string
code:
type: string
# 1. 从 OpenAPI 生成后端代码 (Spring Boot 示例)
openapi-generator generate \
-i openapi.yaml \
-g spring \
-o ./backend \
--additional-properties=interfaceOnly=true
# 2. 生成前端 TypeScript 客户端
openapi-generator generate \
-i openapi.yaml \
-g typescript-axios \
-o ./frontend/src/api
# 3. 生成 API 文档站点
redoc-cli bundle openapi.yaml -o docs/index.html
# 4. 验证 OpenAPI 规范
swagger-cli validate openapi.yaml
# schema.graphql
# 标量类型扩展
scalar DateTime
scalar JSON
scalar Upload
# 枚举类型
enum UserRole {
USER
ADMIN
SUPER_ADMIN
}
enum UserStatus {
ACTIVE
INACTIVE
BANNED
}
enum SortOrder {
ASC
DESC
}
# 主类型
type User @auth(rules: [{allow: authenticated}]) {
id: ID!
email: String!
username: String!
status: UserStatus!
role: UserRole!
profile: UserProfile
posts(first: Int, after: String): PostConnection!
comments(first: Int, after: String): CommentConnection!
createdAt: DateTime!
updatedAt: DateTime!
}
type UserProfile {
firstName: String
lastName: String
avatar: String
bio: String
location: String
website: String
}
type Post {
id: ID!
title: String!
slug: String!
content: String!
excerpt: String
author: User!
status: PostStatus!
tags: [Tag!]
comments(first: Int, after: String): CommentConnection!
likeCount: Int!
viewCount: Int!
publishedAt: DateTime
createdAt: DateTime!
updatedAt: DateTime!
}
enum PostStatus {
DRAFT
PUBLISHED
ARCHIVED
}
type Tag {
id: ID!
name: String!
slug: String!
postCount: Int!
}
type Comment {
id: ID!
content: String!
author: User!
post: Post!
parent: Comment
replies(first: Int, after: String): CommentConnection!
createdAt: DateTime!
}
# 连接类型 (分页)
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type UserEdge {
node: User!
cursor: String!
}
type PostConnection {
edges: [PostEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type PostEdge {
node: Post!
cursor: String!
}
type CommentConnection {
edges: [CommentEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type CommentEdge {
node: Comment!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
# 查询类型
type Query {
# 用户查询
user(id: ID!): User
users(
filter: UserFilter
first: Int = 20
after: String
sortBy: UserSortBy
order: SortOrder = DESC
): UserConnection!
# 文章查询
post(slug: String!): Post
posts(
filter: PostFilter
first: Int = 20
after: String
): PostConnection!
# 标签查询
tag(slug: String!): Tag
tags(first: Int = 50): [Tag!]!
# 搜索
searchUsers(query: String!, first: Int = 20): UserConnection!
searchPosts(query: String!, first: Int = 20): PostConnection!
# 当前登录用户
me: User
}
# 输入类型
input UserFilter {
status: UserStatus
role: UserRole
createdAfter: DateTime
createdBefore: DateTime
}
input PostFilter {
status: PostStatus
authorId: ID
tagId: ID
publishedAfter: DateTime
publishedBefore: DateTime
}
input UserSortBy {
field: UserSortField!
order: SortOrder
}
enum UserSortField {
CREATED_AT
UPDATED_AT
USERNAME
EMAIL
}
# 变更类型
type Mutation {
# 认证
login(email: String!, password: String!): AuthPayload!
register(input: RegisterInput!): AuthPayload!
refreshToken(refreshToken: String!): AuthPayload!
logout: Boolean!
# 用户管理
createUser(input: CreateUserInput!): CreateUserPayload!
updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
deleteUser(id: ID!): DeleteUserPayload!
# 文章管理
createPost(input: CreatePostInput!): CreatePostPayload!
updatePost(id: ID!, input: UpdatePostInput!): UpdatePostPayload!
deletePost(id: ID!): DeletePostPayload!
publishPost(id: ID!): PublishPostPayload!
# 评论管理
createComment(input: CreateCommentInput!): CreateCommentPayload!
deleteComment(id: ID!): DeleteCommentPayload!
# 文件上传
uploadAvatar(file: Upload!): UploadPayload!
}
# Payload 类型
type AuthPayload {
token: String!
refreshToken: String!
user: User!
expiresIn: Int!
}
type RegisterInput {
email: String!
password: String!
username: String!
profile: UserProfileInput
}
type CreateUserInput {
email: String!
password: String!
username: String!
role: UserRole
status: UserStatus
profile: UserProfileInput
}
type UserProfileInput {
firstName: String
lastName: String
avatar: String
bio: String
}
type CreateUserPayload {
user: User
errors: [Error!]
}
type UpdateUserInput {
email: String
username: String
status: UserStatus
role: UserRole
profile: UserProfileInput
}
type UpdateUserPayload {
user: User
errors: [Error!]
}
type DeleteUserPayload {
success: Boolean!
errors: [Error!]
}
type CreatePostInput {
title: String!
content: String!
excerpt: String
tags: [String!]
status: PostStatus
}
type CreatePostPayload {
post: Post
errors: [Error!]
}
# 错误类型
type Error {
code: ErrorCode!
message: String!
field: String
metadata: JSON
}
enum ErrorCode {
VALIDATION_ERROR
NOT_FOUND
UNAUTHORIZED
FORBIDDEN
CONFLICT
INTERNAL_ERROR
}
# 订阅类型
type Subscription {
# 实时通知
userNotification(userId: ID!): Notification!
# 文章更新
postUpdated(postId: ID!): Post!
# 新评论
newComment(postId: ID!): Comment!
}
type Notification {
id: ID!
type: NotificationType!
message: String!
read: Boolean!
createdAt: DateTime!
}
enum NotificationType {
NEW_COMMENT
NEW_LIKE
NEW_FOLLOWER
SYSTEM
}
// resolvers.ts
import { DataLoaderContext } from './loaders';
interface Context {
userId: string | null;
loaders: DataLoaderContext;
prisma: PrismaClient;
}
export const resolvers = {
Query: {
user: async (_, { id }, context: Context) => {
return context.prisma.user.findUnique({ where: { id } });
},
users: async (_, { first, after, filter }, context: Context) => {
const cursor = after ? { id: after } : undefined;
const [users, totalCount] = await Promise.all([
context.prisma.user.findMany({
where: filter,
first: first + 1,
cursor,
orderBy: { createdAt: 'desc' }
}),
context.prisma.user.count({ where: filter })
]);
const hasNextPage = users.length > first;
const edges = users.slice(0, first).map(user => ({
node: user,
cursor: user.id
}));
return {
edges,
pageInfo: {
hasNextPage,
hasPreviousPage: !!after,
endCursor: edges[edges.length - 1]?.cursor
},
totalCount
};
},
me: async (_, __, context: Context) => {
if (!context.userId) return null;
return context.prisma.user.findUnique({
where: { id: context.userId }
});
}
},
Mutation: {
createUser: async (_, { input }, context: Context) => {
try {
const user = await context.prisma.user.create({
data: {
email: input.email,
password: await hashPassword(input.password),
username: input.username,
role: input.role || 'USER',
status: input.status || 'ACTIVE',
profile: input.profile ? {
create: input.profile
} : undefined
},
include: { profile: true }
});
return { user, errors: [] };
} catch (error) {
if (error.code === 'P2002') {
return {
user: null,
errors: [{
code: 'CONFLICT',
message: '邮箱已被注册',
field: 'email'
}]
};
}
throw error;
}
}
},
User: {
profile: (parent, _, context: Context) => {
return context.loaders.profileLoader.load(parent.id);
},
posts: (parent, { first, after }, context: Context) => {
// 实现分页逻辑
}
},
Post: {
author: (parent, _, context: Context) => {
return context.loaders.userLoader.load(parent.authorId);
},
comments: (parent, { first, after }, context: Context) => {
// 实现分页逻辑
}
}
};
# graphql-codegen.yml
schema: 'src/schema.graphql'
documents: 'src/**/*.graphql'
generates:
src/generated/graphql.ts:
plugins:
- typescript
- typescript-resolvers
config:
contextType: '../context#Context'
useTypeImports: true
src/generated/types.ts:
plugins:
- typescript-operations
./graphql.schema.json:
plugins:
- introspection
# 运行生成
npx graphql-codegen --config graphql-codegen.yml
// Jenkinsfile
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'registry.example.com'
IMAGE_NAME = 'myapp-backend'
K8S_NAMESPACE = 'production'
SONAR_HOST = 'https://sonarqube.example.com'
}
stages {
stage('Checkout') {
steps {
checkout scm
script {
env.GIT_COMMIT_SHORT = sh(
script: 'git rev-parse --short HEAD',
returnStdout: true
).trim()
}
}
}
stage('Code Quality') {
parallel {
stage('SonarQube Scan') {
steps {
withSonarQubeEnv('SonarQube') {
sh '''
sonar-scanner \
-Dsonar.projectKey=myapp-backend \
-Dsonar.sources=src \
-Dsonar.host.url=${SONAR_HOST} \
-Dsonar.login=${SONAR_TOKEN}
'''
}
}
}
stage('Security Scan') {
steps {
sh 'npm audit --audit-level=high || true'
sh 'snyk test --severity-threshold=high || true'
}
}
}
}
stage('Unit Test') {
steps {
sh 'npm run test:coverage'
junit allowEmptyResults: true, testResults: 'reports/junit/*.xml'
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'reports/coverage',
reportFiles: 'index.html',
reportName: 'Code Coverage Report'
])
}
}
stage('Build Docker Image') {
steps {
script {
docker.build("${DOCKER_REGISTRY}/${IMAGE_NAME}:${GIT_COMMIT_SHORT}")
}
}
}
stage('Push to Registry') {
steps {
script {
docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-credentials') {
docker.image("${DOCKER_REGISTRY}/${IMAGE_NAME}:${GIT_COMMIT_SHORT}").push()
docker.image("${DOCKER_REGISTRY}/${IMAGE_NAME}:${GIT_COMMIT_SHORT}").push('latest')
}
}
}
}
stage('Deploy to K8s') {
when {
branch 'main'
}
steps {
sh '''
kubectl set image deployment/myapp-backend \
backend=${DOCKER_REGISTRY}/${IMAGE_NAME}:${GIT_COMMIT_SHORT} \
-n ${K8S_NAMESPACE}
kubectl rollout status deployment/myapp-backend -n ${K8S_NAMESPACE}
'''
}
}
stage('Integration Test') {
when {
branch 'main'
}
steps {
sh 'npm run test:integration'
}
}
stage('UI E2E Test') {
when {
branch 'main'
}
steps {
sh 'npm run test:e2e'
archiveArtifacts artifacts: 'reports/e2e/**/*.png', fingerprint: true
}
}
stage('Notify') {
always {
script {
if (currentBuild.result == 'SUCCESS') {
slackSend(color: 'good', message: "✅ 部署成功:${env.JOB_NAME} #${env.BUILD_NUMBER}")
} else {
slackSend(color: 'danger', message: "❌ 部署失败:${env.JOB_NAME} #${env.BUILD_NUMBER}")
}
}
}
}
}
post {
always {
cleanWs()
}
failure {
emailext(
subject: "构建失败:${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: """请查看:${env.BUILD_URL}""",
to: 'dev-team@example.com'
)
}
}
}
# 多阶段构建优化
FROM node:20-alpine AS builder
WORKDIR /app
# 复制依赖定义
COPY package*.json ./
# 安装依赖 (利用缓存)
RUN npm ci --only=production && npm cache clean --force
# 复制源代码
COPY . .
# 构建应用
RUN npm run build
# 生产镜像
FROM node:20-alpine AS production
# 创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
# 从 builder 阶段复制
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/package.json ./
# 切换到非 root 用户
USER nodejs
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node dist/healthcheck.js
# 暴露端口
EXPOSE 3000
# 启动命令
CMD ["node", "dist/server.js"]
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-backend
namespace: production
labels:
app: myapp-backend
version: v1
spec:
replicas: 3
selector:
matchLabels:
app: myapp-backend
template:
metadata:
labels:
app: myapp-backend
version: v1
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "3000"
spec:
containers:
- name: backend
image: registry.example.com/myapp-backend:latest
ports:
- containerPort: 3000
name: http
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
env:
- name: NODE_ENV
value: "production"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secret
key: url
livenessProbe:
httpGet:
path: /health/live
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health/ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts:
- name: logs
mountPath: /app/logs
volumes:
- name: logs
emptyDir: {}
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: myapp-backend
topologyKey: kubernetes.io/hostname
---
apiVersion: v1
kind: Service
metadata:
name: myapp-backend-service
namespace: production
spec:
selector:
app: myapp-backend
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
namespace: production
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- api.example.com
secretName: myapp-tls
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp-backend-service
port:
number: 80
| 阶段 | AI 自动化内容 | 人工审核点 | 审核工具 |
|---|---|---|---|
| PRD 设计 | 需求文档草稿、用户故事生成 | 需求准确性、业务逻辑验证 | Notion + Review Comments |
| 技术方案 | 架构图、API 设计初稿 | 技术选型、安全性评估 | Architecture Decision Record (ADR) |
| 代码实现 | 业务代码、单元测试 | Code Review、核心算法 | GitHub PR + SonarQube |
| 测试验收 | 测试用例执行、报告生成 | 边界场景、用户体验 | TestRail + Manual Testing |
| 生产部署 | CI/CD 流水线执行 | 上线审批、回滚预案 | Jenkins Approval + Change Management |
# skills-config.yaml
skills:
# 产品技能
- name: prd-generator
description: 根据需求生成 PRD 文档
trigger: "/generate-prd"
model: claude-sonnet-4
tools:
- mcp-notion
- mcp-jira
output: markdown
# 后端技能
- name: api-designer
description: 设计 RESTful/GraphQL API
trigger: "/design-api"
model: claude-opus-4
tools:
- mcp-github
- swagger-validator
output: openapi-yaml
- name: code-generator
description: 根据 API 规范生成代码
trigger: "/generate-code"
model: claude-code
tools:
- file-system
- git
output: source-code
# 测试技能
- name: test-writer
description: 自动生成单元测试
trigger: "/write-tests"
model: claude-sonnet-4
tools:
- jest
- pytest
output: test-files
# DevOps 技能
- name: pipeline-builder
description: 构建 CI/CD 流水线
trigger: "/create-pipeline"
model: claude-sonnet-4
tools:
- jenkins-api
- docker
- kubectl
output: jenkinsfile
# 代码审查技能
- name: code-reviewer
description: 自动 Code Review
trigger: "/review-pr"
model: claude-opus-4
tools:
- github-api
- sonarqube
output: review-comments
# 钩子配置
hooks:
before-commit:
- run: "npm run lint"
- run: "npm run test"
- run: "claude /review-changes"
after-deploy:
- run: "kubectl rollout status deployment/myapp"
- notify: "slack:#deployments"
# CLAUDE.md - 项目级 AI 助手配置
## 项目概述
这是一个基于微服务架构的电商平台系统,采用前后端分离设计。
## 技术栈
- **后端**: Node.js + NestJS + PostgreSQL
- **前端**: React 18 + TypeScript + TailwindCSS
- **API**: RESTful (OpenAPI 3.0) + GraphQL
- **部署**: Docker + Kubernetes (KubeSphere)
- **CI/CD**: Jenkins Pipeline
## 代码规范
### TypeScript
- 使用严格模式,禁止使用 `any`
- 所有函数必须有返回类型注解
- 使用 ESLint + Prettier 格式化
### 命名约定
- 文件:kebab-case (e.g., `user-service.ts`)
- 类:PascalCase (e.g., `UserService`)
- 函数/变量:camelCase (e.g., `getUserById`)
- 常量:UPPER_SNAKE_CASE (e.g., `MAX_RETRY_COUNT`)
### 测试要求
- 单元测试覆盖率 ≥ 80%
- 关键业务逻辑覆盖率 ≥ 95%
- 使用 Jest 框架
- 测试文件命名:`*.spec.ts`
## API 设计规范
- RESTful 遵循本仓库 `/docs/openapi.yaml`
- GraphQL Schema 位于 `/apps/api/src/schema.graphql`
- 所有接口必须有完整的错误处理
- 响应格式统一使用 `{ data, error, meta }`
## 数据库规范
- 使用 Prisma ORM
- 所有表必须有 `created_at` 和 `updated_at`
- 软删除使用 `deleted_at` 字段
- 索引命名:`idx_table_column`
## Git 工作流
- 主分支:`main` (受保护)
- 开发分支:`develop`
- 功能分支:`feature/xxx`
- 修复分支:`fix/xxx`
- Commit 信息遵循 Conventional Commits
## 环境变量
```bash
DATABASE_URL=postgresql://user:pass@localhost:5432/dbname
JWT_SECRET=your-secret-key
NODE_ENV=development|production
```
## 常用命令
```bash
# 开发
npm run dev # 启动开发服务器
npm run test:watch # 监听模式运行测试
# 构建
npm run build # 构建生产版本
npm run docker:build # 构建 Docker 镜像
# 部署
npm run deploy:staging # 部署到预发布
npm run deploy:prod # 部署到生产 (需审批)
```
## 安全检查清单
- [ ] SQL 注入防护 (使用参数化查询)
- [ ] XSS 防护 (Sanitize 用户输入)
- [ ] CSRF Token 验证
- [ ] 敏感信息不记录日志
- [ ] 速率限制配置
- [ ] CORS 白名单配置
## AI 辅助规则
1. 生成代码后必须运行测试验证
2. 修改超过 5 个文件时需创建 PR
3. 涉及数据库变更需先更新 Prisma Schema
4. 新增 API 必须同步更新 OpenAPI 文档
5. 遇到不确定时主动询问人类开发者