design - 设计命令
design 命令是 Claude Code 的智能系统设计工具,帮助开发者创建清晰的架构设计、接口规范和系统文档。
命令概述
design 命令提供:
- 系统架构设计
- 数据库模型设计
- API 接口设计
- UI/UX 设计规范
- 技术方案设计
基本用法
创建新设计
bash
# 完整系统设计
claude design --type system --name "用户管理系统"
# API 设计
claude design --type api --name "用户API" --version v1
# 数据库设计
claude design --type database --name "用户数据模型"
# UI 组件设计
claude design --type component --name "用户资料卡片"基于现有代码设计
bash
# 从现有代码生成设计文档
claude design --from-code ./src/components/UserProfile.jsx
# 逆向工程整个模块
claude design --reverse-engineer ./src/modules/user-management配置选项
基础选项
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
--type | string | system | 设计类型 |
--format | string | markdown | 输出格式 |
--detail | string | standard | 详细程度 |
--interactive | boolean | false | 交互式设计模式 |
输出选项
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
--output | string | ./docs/design | 输出目录 |
--template | string | - | 使用的模板 |
--diagrams | boolean | true | 生成图表 |
--examples | boolean | true | 包含示例代码 |
设计类型详解
1. 系统架构设计
微服务架构设计
bash
# 设计微服务架构
claude design --type system --architecture microservices --name "电商平台"生成的架构文档:
markdown
# 电商平台系统架构设计
## 1. 架构概览
### 整体架构
```mermaid
graph TB
subgraph "客户端层"
WebApp[Web应用]
MobileApp[移动应用]
AdminPanel[管理后台]
end
subgraph "网关层"
APIGateway[API网关]
LoadBalancer[负载均衡器]
end
subgraph "服务层"
UserService[用户服务]
ProductService[商品服务]
OrderService[订单服务]
PaymentService[支付服务]
NotificationService[通知服务]
end
subgraph "数据层"
UserDB[(用户数据库)]
ProductDB[(商品数据库)]
OrderDB[(订单数据库)]
Cache[(Redis缓存)]
end
subgraph "基础设施"
MessageQueue[消息队列]
FileStorage[文件存储]
LogCenter[日志中心]
Monitor[监控中心]
end
WebApp --> APIGateway
MobileApp --> APIGateway
AdminPanel --> APIGateway
APIGateway --> LoadBalancer
LoadBalancer --> UserService
LoadBalancer --> ProductService
LoadBalancer --> OrderService
LoadBalancer --> PaymentService
UserService --> UserDB
ProductService --> ProductDB
OrderService --> OrderDB
OrderService --> PaymentService
UserService --> Cache
ProductService --> Cache
OrderService --> MessageQueue
PaymentService --> MessageQueue
NotificationService --> MessageQueue服务详细设计
用户服务 (User Service)
职责: 用户身份认证、用户信息管理、权限控制
技术栈:
- 框架: Spring Boot 3.0
- 数据库: PostgreSQL
- 缓存: Redis
- 消息队列: RabbitMQ
核心功能:
- 用户注册/登录
- 用户信息CRUD
- 权限管理
- 身份验证
API 端点:
POST /api/v1/users/register # 用户注册
POST /api/v1/users/login # 用户登录
GET /api/v1/users/profile # 获取用户信息
PUT /api/v1/users/profile # 更新用户信息
DELETE /api/v1/users/{id} # 删除用户数据模型:
sql
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
username VARCHAR(100) UNIQUE NOT NULL,
first_name VARCHAR(100),
last_name VARCHAR(100),
phone VARCHAR(20),
avatar_url VARCHAR(255),
status VARCHAR(20) DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);商品服务 (Product Service)
职责: 商品信息管理、分类管理、库存管理
核心功能:
- 商品CRUD操作
- 分类管理
- 库存管理
- 价格管理
事件发布:
- ProductCreated
- ProductUpdated
- StockChanged
- PriceChanged
通信模式
同步通信 (HTTP/REST)
- 用户查询个人信息
- 商品信息查询
- 实时数据获取
异步通信 (消息队列)
- 订单创建通知
- 库存更新
- 邮件发送
- 数据同步
数据一致性策略
最终一致性
对于非关键业务数据,采用最终一致性:
- 用户信息更新
- 商品信息同步
- 日志记录
强一致性
对于关键业务数据,采用强一致性:
- 订单创建
- 支付处理
- 库存扣减
容错设计
熔断器模式
java
@Component
public class PaymentServiceClient {
@CircuitBreaker(name = "payment-service", fallbackMethod = "fallbackPayment")
public PaymentResult processPayment(PaymentRequest request) {
return paymentServiceCall(request);
}
public PaymentResult fallbackPayment(PaymentRequest request, Exception ex) {
return PaymentResult.failed("服务暂时不可用,请稍后重试");
}
}重试机制
yaml
resilience4j:
retry:
instances:
payment-service:
max-attempts: 3
wait-duration: 1s
exponential-backoff-multiplier: 2性能设计
缓存策略
- L1缓存: 本地缓存 (Caffeine)
- L2缓存: 分布式缓存 (Redis)
- CDN缓存: 静态资源缓存
数据库优化
- 读写分离
- 分库分表
- 索引优化
- 连接池配置
安全设计
身份认证
- JWT Token 认证
- OAuth2 集成
- 双因素认证
数据安全
- 数据加密存储
- 传输加密 (TLS)
- 敏感信息脱敏
监控设计
应用监控
- Prometheus + Grafana
- 自定义业务指标
- 告警规则配置
日志管理
- ELK Stack (Elasticsearch + Logstash + Kibana)
- 结构化日志
- 分布式链路追踪
2. 部署架构
容器化部署
yaml
# docker-compose.yml
version: '3.8'
services:
user-service:
image: ecommerce/user-service:latest
ports:
- "8081:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- DATABASE_URL=postgresql://postgres:5432/userdb
depends_on:
- postgres
- redis
product-service:
image: ecommerce/product-service:latest
ports:
- "8082:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- DATABASE_URL=postgresql://postgres:5432/productdbKubernetes 部署
yaml
# k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: ecommerce/user-service:latest
ports:
- containerPort: 8080
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secret
key: url3. 技术决策记录
ADR-001: 选择微服务架构
状态: 已接受 决策日期: 2024-01-15
背景: 需要构建一个可扩展的电商平台
决策: 采用微服务架构
理由:
- 团队规模较大 (30+ 开发者)
- 不同业务模块有不同的扩展需求
- 希望使用不同的技术栈
- 需要独立部署和发布
后果:
- 增加了系统复杂性
- 需要额外的基础设施
- 网络通信开销
- 数据一致性挑战
ADR-002: 选择 PostgreSQL 作为主数据库
状态: 已接受
决策日期: 2024-01-16
背景: 需要选择合适的数据库技术
决策: 使用 PostgreSQL 作为主要关系型数据库
理由:
- 优秀的 ACID 特性
- 丰富的数据类型支持
- 强大的查询优化器
- 活跃的社区支持
4. 风险评估与缓解
高风险项
服务间通信失败
- 风险: 服务不可用导致业务中断
- 缓解: 实现熔断器和降级策略
数据一致性问题
- 风险: 分布式事务失败
- 缓解: 使用Saga模式和补偿事务
性能瓶颈
- 风险: 高并发下系统性能下降
- 缓解: 实施缓存策略和负载均衡
中等风险项
技术栈多样性
- 风险: 维护成本增加
- 缓解: 制定技术标准和培训计划
运维复杂性
- 风险: 部署和监控复杂
- 缓解: 自动化工具和标准化流程
#### 单体架构设计
```bash
# 设计单体应用架构
claude design --type system --architecture monolith --name "内容管理系统"2. API 接口设计
RESTful API 设计
bash
# 设计RESTful API
claude design --type api --style rest --name "用户管理API"生成的API设计文档:
markdown
# 用户管理API设计文档
## API 概览
### 基础信息
- **Base URL**: `https://api.example.com/v1`
- **认证方式**: Bearer Token (JWT)
- **数据格式**: JSON
- **字符编码**: UTF-8
### 设计原则
1. **RESTful**: 遵循REST架构风格
2. **一致性**: 统一的命名和响应格式
3. **版本控制**: 通过URL路径进行版本管理
4. **安全性**: 完善的认证和授权机制
## 资源设计
### 用户资源 (Users)
#### 1. 创建用户
```http
POST /v1/users
Content-Type: application/json
Authorization: Bearer {token}
{
"email": "user@example.com",
"password": "securePassword123",
"username": "johndoe",
"profile": {
"firstName": "John",
"lastName": "Doe",
"phone": "+1234567890"
}
}响应:
json
{
"success": true,
"data": {
"id": 12345,
"email": "user@example.com",
"username": "johndoe",
"profile": {
"firstName": "John",
"lastName": "Doe",
"phone": "+1234567890",
"avatar": null
},
"status": "active",
"createdAt": "2024-01-20T10:30:00Z",
"updatedAt": "2024-01-20T10:30:00Z"
},
"meta": {
"version": "v1",
"timestamp": "2024-01-20T10:30:00Z"
}
}2. 获取用户列表
http
GET /v1/users?page=1&limit=20&status=active&sort=createdAt:desc
Authorization: Bearer {token}查询参数:
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|---|---|---|---|---|
page | integer | 否 | 1 | 页码 |
limit | integer | 否 | 20 | 每页数量 (最大100) |
status | string | 否 | - | 用户状态筛选 |
sort | string | 否 | createdAt:desc | 排序字段和方向 |
search | string | 否 | - | 搜索关键词 |
响应:
json
{
"success": true,
"data": {
"users": [
{
"id": 12345,
"email": "user@example.com",
"username": "johndoe",
"profile": {
"firstName": "John",
"lastName": "Doe"
},
"status": "active",
"createdAt": "2024-01-20T10:30:00Z"
}
],
"pagination": {
"currentPage": 1,
"perPage": 20,
"total": 150,
"totalPages": 8,
"hasNext": true,
"hasPrev": false
}
}
}错误处理设计
标准错误响应
json
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "输入数据验证失败",
"details": [
{
"field": "email",
"message": "邮箱格式无效",
"code": "INVALID_FORMAT"
},
{
"field": "password",
"message": "密码长度不能少于8位",
"code": "TOO_SHORT"
}
],
"timestamp": "2024-01-20T10:30:00Z",
"requestId": "req_1234567890"
}
}HTTP状态码使用
| 状态码 | 含义 | 使用场景 |
|---|---|---|
| 200 | OK | 成功获取资源 |
| 201 | Created | 成功创建资源 |
| 204 | No Content | 成功删除资源 |
| 400 | Bad Request | 请求参数错误 |
| 401 | Unauthorized | 未认证 |
| 403 | Forbidden | 权限不足 |
| 404 | Not Found | 资源不存在 |
| 409 | Conflict | 资源冲突 |
| 422 | Unprocessable Entity | 语义错误 |
| 429 | Too Many Requests | 请求频率限制 |
| 500 | Internal Server Error | 服务器内部错误 |
认证和授权
JWT Token 结构
json
{
"header": {
"alg": "HS256",
"typ": "JWT"
},
"payload": {
"sub": "12345",
"username": "johndoe",
"email": "user@example.com",
"role": "user",
"permissions": ["read:profile", "write:profile"],
"iat": 1642680000,
"exp": 1642683600
}
}权限控制
http
# 需要特定权限的端点
GET /v1/admin/users
Authorization: Bearer {token}
Required-Permission: read:all_usersAPI 版本控制
URL版本控制
/v1/users # 版本1
/v2/users # 版本2版本兼容性
- 向后兼容: 新版本保持对旧版本的兼容
- 废弃通知: 提前通知版本废弃计划
- 迁移指南: 提供版本升级指南
速率限制
限制策略
http
# 响应头
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1642680000
X-RateLimit-Window: 3600限制级别
- 用户级别: 每个用户的请求限制
- IP级别: 每个IP地址的请求限制
- 端点级别: 特定端点的请求限制
文档和SDK
自动化文档生成
- OpenAPI 3.0 规范
- Swagger UI 界面
- 代码示例生成
SDK支持
javascript
// JavaScript SDK 示例
import { UserAPI } from '@example/api-client';
const userAPI = new UserAPI({
baseURL: 'https://api.example.com/v1',
apiKey: 'your-api-key'
});
// 创建用户
const user = await userAPI.createUser({
email: 'user@example.com',
password: 'password123',
profile: {
firstName: 'John',
lastName: 'Doe'
}
});
// 获取用户列表
const users = await userAPI.getUsers({
page: 1,
limit: 20,
status: 'active'
});
### 3. 数据库设计
#### 关系型数据库设计
```bash
# 设计数据库模型
claude design --type database --engine postgresql --name "电商数据模型"生成的数据库设计:
sql
-- 电商数据模型设计
-- 数据库: PostgreSQL 15+
-- 字符集: UTF8
-- 排序规则: zh_CN.UTF-8
-- 用户表
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
username VARCHAR(100) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
salt VARCHAR(32) NOT NULL,
first_name VARCHAR(100),
last_name VARCHAR(100),
phone VARCHAR(20),
date_of_birth DATE,
gender VARCHAR(10) CHECK (gender IN ('male', 'female', 'other')),
avatar_url VARCHAR(255),
status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'inactive', 'suspended', 'deleted')),
email_verified BOOLEAN DEFAULT FALSE,
phone_verified BOOLEAN DEFAULT FALSE,
last_login_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 用户地址表
CREATE TABLE user_addresses (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
type VARCHAR(20) DEFAULT 'shipping' CHECK (type IN ('shipping', 'billing')),
is_default BOOLEAN DEFAULT FALSE,
recipient_name VARCHAR(100) NOT NULL,
phone VARCHAR(20),
country VARCHAR(100) NOT NULL,
province VARCHAR(100),
city VARCHAR(100) NOT NULL,
district VARCHAR(100),
street_address TEXT NOT NULL,
postal_code VARCHAR(20),
latitude DECIMAL(10, 8),
longitude DECIMAL(11, 8),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 商品分类表
CREATE TABLE categories (
id BIGSERIAL PRIMARY KEY,
parent_id BIGINT REFERENCES categories(id) ON DELETE SET NULL,
name VARCHAR(100) NOT NULL,
slug VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
image_url VARCHAR(255),
sort_order INTEGER DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 商品表
CREATE TABLE products (
id BIGSERIAL PRIMARY KEY,
category_id BIGINT REFERENCES categories(id) ON DELETE SET NULL,
sku VARCHAR(100) UNIQUE NOT NULL,
name VARCHAR(200) NOT NULL,
slug VARCHAR(200) UNIQUE NOT NULL,
description TEXT,
short_description VARCHAR(500),
price DECIMAL(10, 2) NOT NULL CHECK (price >= 0),
compare_price DECIMAL(10, 2) CHECK (compare_price >= price),
cost_price DECIMAL(10, 2),
weight DECIMAL(8, 3),
dimensions JSONB, -- {length: 10, width: 5, height: 3}
status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'inactive', 'draft', 'archived')),
visibility VARCHAR(20) DEFAULT 'public' CHECK (visibility IN ('public', 'private', 'hidden')),
track_inventory BOOLEAN DEFAULT TRUE,
inventory_quantity INTEGER DEFAULT 0 CHECK (inventory_quantity >= 0),
allow_backorder BOOLEAN DEFAULT FALSE,
requires_shipping BOOLEAN DEFAULT TRUE,
is_digital BOOLEAN DEFAULT FALSE,
meta_title VARCHAR(200),
meta_description VARCHAR(500),
tags TEXT[], -- PostgreSQL数组类型
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 商品图片表
CREATE TABLE product_images (
id BIGSERIAL PRIMARY KEY,
product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE CASCADE,
url VARCHAR(255) NOT NULL,
alt_text VARCHAR(200),
sort_order INTEGER DEFAULT 0,
is_primary BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 商品属性表
CREATE TABLE product_attributes (
id BIGSERIAL PRIMARY KEY,
product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL,
value TEXT NOT NULL,
sort_order INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 订单表
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
order_number VARCHAR(50) UNIQUE NOT NULL,
user_id BIGINT REFERENCES users(id) ON DELETE SET NULL,
status VARCHAR(20) DEFAULT 'pending' CHECK (status IN ('pending', 'confirmed', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded')),
payment_status VARCHAR(20) DEFAULT 'pending' CHECK (payment_status IN ('pending', 'paid', 'failed', 'refunded', 'partially_refunded')),
fulfillment_status VARCHAR(20) DEFAULT 'unfulfilled' CHECK (fulfillment_status IN ('unfulfilled', 'partial', 'fulfilled')),
-- 金额信息
subtotal DECIMAL(10, 2) NOT NULL DEFAULT 0,
tax_amount DECIMAL(10, 2) DEFAULT 0,
shipping_amount DECIMAL(10, 2) DEFAULT 0,
discount_amount DECIMAL(10, 2) DEFAULT 0,
total_amount DECIMAL(10, 2) NOT NULL DEFAULT 0,
-- 地址信息 (JSON存储,避免外键依赖)
billing_address JSONB,
shipping_address JSONB,
-- 其他信息
notes TEXT,
customer_notes TEXT,
processed_at TIMESTAMP,
shipped_at TIMESTAMP,
delivered_at TIMESTAMP,
cancelled_at TIMESTAMP,
cancel_reason TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 订单商品表
CREATE TABLE order_items (
id BIGSERIAL PRIMARY KEY,
order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
product_id BIGINT REFERENCES products(id) ON DELETE SET NULL,
-- 商品快照 (防止商品信息变更影响历史订单)
product_name VARCHAR(200) NOT NULL,
product_sku VARCHAR(100),
product_image_url VARCHAR(255),
quantity INTEGER NOT NULL CHECK (quantity > 0),
unit_price DECIMAL(10, 2) NOT NULL CHECK (unit_price >= 0),
total_price DECIMAL(10, 2) NOT NULL CHECK (total_price >= 0),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 购物车表
CREATE TABLE carts (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT REFERENCES users(id) ON DELETE CASCADE,
session_id VARCHAR(255), -- 支持匿名用户购物车
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT cart_user_or_session CHECK (user_id IS NOT NULL OR session_id IS NOT NULL)
);
-- 购物车商品表
CREATE TABLE cart_items (
id BIGSERIAL PRIMARY KEY,
cart_id BIGINT NOT NULL REFERENCES carts(id) ON DELETE CASCADE,
product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE CASCADE,
quantity INTEGER NOT NULL CHECK (quantity > 0),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(cart_id, product_id)
);
-- 支付记录表
CREATE TABLE payments (
id BIGSERIAL PRIMARY KEY,
order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
payment_method VARCHAR(50) NOT NULL, -- 'credit_card', 'paypal', 'alipay', etc.
payment_provider VARCHAR(50), -- 'stripe', 'paypal', 'alipay', etc.
transaction_id VARCHAR(255),
amount DECIMAL(10, 2) NOT NULL CHECK (amount > 0),
currency VARCHAR(3) DEFAULT 'CNY',
status VARCHAR(20) DEFAULT 'pending' CHECK (status IN ('pending', 'processing', 'succeeded', 'failed', 'cancelled', 'refunded')),
failure_reason TEXT,
metadata JSONB, -- 存储支付提供商返回的额外数据
processed_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 优惠券表
CREATE TABLE coupons (
id BIGSERIAL PRIMARY KEY,
code VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
description TEXT,
type VARCHAR(20) NOT NULL CHECK (type IN ('percentage', 'fixed_amount', 'free_shipping')),
value DECIMAL(10, 2) NOT NULL CHECK (value > 0),
minimum_amount DECIMAL(10, 2) DEFAULT 0,
usage_limit INTEGER, -- 总使用次数限制
usage_limit_per_customer INTEGER DEFAULT 1, -- 每个客户使用次数限制
used_count INTEGER DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
starts_at TIMESTAMP,
expires_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 优惠券使用记录表
CREATE TABLE coupon_usages (
id BIGSERIAL PRIMARY KEY,
coupon_id BIGINT NOT NULL REFERENCES coupons(id) ON DELETE CASCADE,
order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
user_id BIGINT REFERENCES users(id) ON DELETE SET NULL,
discount_amount DECIMAL(10, 2) NOT NULL,
used_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(coupon_id, order_id)
);
-- 评论表
CREATE TABLE reviews (
id BIGSERIAL PRIMARY KEY,
product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE CASCADE,
user_id BIGINT REFERENCES users(id) ON DELETE SET NULL,
order_item_id BIGINT REFERENCES order_items(id) ON DELETE SET NULL,
rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5),
title VARCHAR(200),
content TEXT NOT NULL,
is_verified_purchase BOOLEAN DEFAULT FALSE,
is_approved BOOLEAN DEFAULT FALSE,
helpful_count INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 索引创建
-- 用户表索引
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_username ON users(username);
CREATE INDEX idx_users_status ON users(status);
CREATE INDEX idx_users_created_at ON users(created_at);
-- 商品表索引
CREATE INDEX idx_products_category_id ON products(category_id);
CREATE INDEX idx_products_sku ON products(sku);
CREATE INDEX idx_products_status ON products(status);
CREATE INDEX idx_products_name ON products USING gin(to_tsvector('chinese', name));
CREATE INDEX idx_products_created_at ON products(created_at);
CREATE INDEX idx_products_price ON products(price);
-- 订单表索引
CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_orders_status ON orders(status);
CREATE INDEX idx_orders_created_at ON orders(created_at);
CREATE INDEX idx_orders_order_number ON orders(order_number);
-- 复合索引
CREATE INDEX idx_order_items_order_product ON order_items(order_id, product_id);
CREATE INDEX idx_cart_items_cart_product ON cart_items(cart_id, product_id);
-- 触发器函数:更新 updated_at 字段
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 为需要的表添加触发器
CREATE TRIGGER update_users_updated_at
BEFORE UPDATE ON users
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_products_updated_at
BEFORE UPDATE ON products
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_orders_updated_at
BEFORE UPDATE ON orders
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- 视图:用户订单统计
CREATE VIEW user_order_stats AS
SELECT
u.id,
u.username,
u.email,
COUNT(o.id) as total_orders,
COALESCE(SUM(o.total_amount), 0) as total_spent,
COALESCE(AVG(o.total_amount), 0) as avg_order_value,
MAX(o.created_at) as last_order_date
FROM users u
LEFT JOIN orders o ON u.id = o.user_id AND o.status != 'cancelled'
GROUP BY u.id, u.username, u.email;
-- 存储过程:更新商品库存
CREATE OR REPLACE FUNCTION update_product_inventory(
p_product_id BIGINT,
p_quantity_change INTEGER
) RETURNS BOOLEAN AS $$
DECLARE
current_quantity INTEGER;
BEGIN
-- 获取当前库存
SELECT inventory_quantity INTO current_quantity
FROM products
WHERE id = p_product_id;
-- 检查库存是否足够
IF current_quantity + p_quantity_change < 0 THEN
RETURN FALSE;
END IF;
-- 更新库存
UPDATE products
SET inventory_quantity = inventory_quantity + p_quantity_change,
updated_at = CURRENT_TIMESTAMP
WHERE id = p_product_id;
RETURN TRUE;
END;
$$ LANGUAGE plpgsql;4. UI 组件设计
React 组件设计
bash
# 设计UI组件
claude design --type component --framework react --name "用户资料卡片"生成的组件设计:
markdown
# 用户资料卡片组件设计
## 组件概览
### 组件名称: UserProfileCard
### 用途: 展示用户基本信息和操作按钮
### 框架: React 18+ with TypeScript
## 设计规范
### 视觉设计
```css
/* 组件样式 */
.user-profile-card {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
padding: 24px;
max-width: 400px;
transition: box-shadow 0.2s ease;
}
.user-profile-card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
.user-avatar {
width: 80px;
height: 80px;
border-radius: 50%;
object-fit: cover;
border: 3px solid #f0f0f0;
}
.user-info {
margin-left: 16px;
flex: 1;
}
.user-name {
font-size: 20px;
font-weight: 600;
color: #1a1a1a;
margin: 0 0 4px 0;
}
.user-email {
font-size: 14px;
color: #666666;
margin: 0 0 8px 0;
}
.user-status {
display: inline-flex;
align-items: center;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status-active {
background: #e7f5e7;
color: #2d7d2d;
}
.status-inactive {
background: #ffeaea;
color: #d32f2f;
}组件接口
typescript
// UserProfileCard.types.ts
export interface UserProfileCardProps {
user: User;
size?: 'small' | 'medium' | 'large';
showActions?: boolean;
actions?: ActionButton[];
onUserClick?: (user: User) => void;
onActionClick?: (action: string, user: User) => void;
className?: string;
style?: React.CSSProperties;
}
export interface User {
id: string | number;
name: string;
email: string;
avatar?: string;
status: 'active' | 'inactive' | 'suspended';
role?: string;
lastLoginAt?: string;
createdAt: string;
}
export interface ActionButton {
key: string;
label: string;
icon?: React.ReactNode;
variant?: 'primary' | 'secondary' | 'danger';
disabled?: boolean;
}组件实现
tsx
// UserProfileCard.tsx
import React from 'react';
import { User, UserProfileCardProps, ActionButton } from './UserProfileCard.types';
import './UserProfileCard.css';
const UserProfileCard: React.FC<UserProfileCardProps> = ({
user,
size = 'medium',
showActions = true,
actions = [],
onUserClick,
onActionClick,
className = '',
style
}) => {
const defaultActions: ActionButton[] = [
{ key: 'edit', label: '编辑', variant: 'primary' },
{ key: 'delete', label: '删除', variant: 'danger' }
];
const finalActions = actions.length > 0 ? actions : defaultActions;
const handleUserClick = () => {
if (onUserClick) {
onUserClick(user);
}
};
const handleActionClick = (actionKey: string, event: React.MouseEvent) => {
event.stopPropagation();
if (onActionClick) {
onActionClick(actionKey, user);
}
};
const getStatusColor = (status: string) => {
switch (status) {
case 'active': return 'status-active';
case 'inactive': return 'status-inactive';
case 'suspended': return 'status-suspended';
default: return 'status-inactive';
}
};
const formatLastLogin = (lastLoginAt?: string) => {
if (!lastLoginAt) return '从未登录';
const date = new Date(lastLoginAt);
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
if (diffDays === 0) return '今天';
if (diffDays === 1) return '昨天';
if (diffDays < 7) return `${diffDays}天前`;
return date.toLocaleDateString('zh-CN');
};
return (
<div
className={`user-profile-card user-profile-card--${size} ${className}`}
style={style}
onClick={handleUserClick}
>
<div className="user-profile-header">
<img
src={user.avatar || '/default-avatar.png'}
alt={`${user.name}的头像`}
className="user-avatar"
onError={(e) => {
(e.target as HTMLImageElement).src = '/default-avatar.png';
}}
/>
<div className="user-info">
<h3 className="user-name">{user.name}</h3>
<p className="user-email">{user.email}</p>
<div className="user-meta">
<span className={`user-status ${getStatusColor(user.status)}`}>
{user.status === 'active' ? '活跃' :
user.status === 'inactive' ? '未激活' : '已暂停'}
</span>
{user.role && (
<span className="user-role">{user.role}</span>
)}
</div>
</div>
</div>
<div className="user-profile-details">
<div className="detail-item">
<span className="detail-label">最后登录:</span>
<span className="detail-value">{formatLastLogin(user.lastLoginAt)}</span>
</div>
<div className="detail-item">
<span className="detail-label">注册时间:</span>
<span className="detail-value">
{new Date(user.createdAt).toLocaleDateString('zh-CN')}
</span>
</div>
</div>
{showActions && finalActions.length > 0 && (
<div className="user-profile-actions">
{finalActions.map((action) => (
<button
key={action.key}
className={`action-button action-button--${action.variant || 'secondary'}`}
disabled={action.disabled}
onClick={(e) => handleActionClick(action.key, e)}
>
{action.icon && <span className="action-icon">{action.icon}</span>}
{action.label}
</button>
))}
</div>
)}
</div>
);
};
export default UserProfileCard;使用示例
tsx
// 基本使用
<UserProfileCard
user={{
id: 1,
name: '张三',
email: 'zhangsan@example.com',
avatar: 'https://example.com/avatar.jpg',
status: 'active',
role: '管理员',
lastLoginAt: '2024-01-20T10:30:00Z',
createdAt: '2024-01-01T00:00:00Z'
}}
/>
// 自定义操作
<UserProfileCard
user={userData}
actions={[
{ key: 'view', label: '查看详情', variant: 'primary' },
{ key: 'message', label: '发送消息', variant: 'secondary' },
{ key: 'suspend', label: '暂停用户', variant: 'danger' }
]}
onActionClick={(action, user) => {
console.log(`执行操作: ${action}`, user);
}}
/>
// 只读模式
<UserProfileCard
user={userData}
showActions={false}
onUserClick={(user) => {
// 跳转到用户详情页
router.push(`/users/${user.id}`);
}}
/>响应式设计
css
/* 响应式适配 */
@media (max-width: 768px) {
.user-profile-card {
padding: 16px;
max-width: 100%;
}
.user-profile-header {
flex-direction: column;
text-align: center;
}
.user-info {
margin-left: 0;
margin-top: 12px;
}
.user-profile-actions {
flex-direction: column;
gap: 8px;
}
}
@media (max-width: 480px) {
.user-avatar {
width: 60px;
height: 60px;
}
.user-name {
font-size: 18px;
}
.action-button {
width: 100%;
}
}可访问性
tsx
// 可访问性增强
<div
className="user-profile-card"
role="button"
tabIndex={0}
aria-label={`用户 ${user.name} 的资料卡片`}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
handleUserClick();
}
}}
>
<img
src={user.avatar}
alt={`${user.name}的头像`}
role="img"
/>
<button
className="action-button"
aria-label={`${action.label} ${user.name}`}
disabled={action.disabled}
>
{action.label}
</button>
</div>测试用例
tsx
// UserProfileCard.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import UserProfileCard from './UserProfileCard';
const mockUser = {
id: 1,
name: '张三',
email: 'zhangsan@example.com',
status: 'active' as const,
createdAt: '2024-01-01T00:00:00Z'
};
describe('UserProfileCard', () => {
test('渲染用户基本信息', () => {
render(<UserProfileCard user={mockUser} />);
expect(screen.getByText('张三')).toBeInTheDocument();
expect(screen.getByText('zhangsan@example.com')).toBeInTheDocument();
expect(screen.getByText('活跃')).toBeInTheDocument();
});
test('点击用户卡片触发回调', () => {
const onUserClick = jest.fn();
render(<UserProfileCard user={mockUser} onUserClick={onUserClick} />);
fireEvent.click(screen.getByRole('button'));
expect(onUserClick).toHaveBeenCalledWith(mockUser);
});
test('点击操作按钮触发回调', () => {
const onActionClick = jest.fn();
render(
<UserProfileCard
user={mockUser}
onActionClick={onActionClick}
actions={[{ key: 'edit', label: '编辑', variant: 'primary' }]}
/>
);
fireEvent.click(screen.getByText('编辑'));
expect(onActionClick).toHaveBeenCalledWith('edit', mockUser);
});
test('隐藏操作按钮', () => {
render(<UserProfileCard user={mockUser} showActions={false} />);
expect(screen.queryByText('编辑')).not.toBeInTheDocument();
expect(screen.queryByText('删除')).not.toBeInTheDocument();
});
});
## 相关命令
- [`analyze`](./analyze.md) - 代码分析命令
- [`build`](./build.md) - 构建命令
- [`generate`](./generate.md) - 代码生成命令
## 最佳实践
### 1. 设计原则
- 遵循单一职责原则
- 保持接口简洁明了
- 考虑扩展性和维护性
### 2. 文档完整性
- 包含详细的API文档
- 提供使用示例
- 说明设计决策和权衡
### 3. 协作效率
- 使用标准化的设计模板
- 及时同步设计变更
- 维护设计版本历史
---
*design 命令 - 将想法转化为蓝图*