关于 feature-spec
Feature Spec 面向产品经理,帮助将功能构想整理为可供实施的详细规格说明。它整合功能需求、技术细节、边界情况、API 契约、数据模型和 UX 流程,供设计与工程团队协作。
主要功能
- 01记录功能和技术需求
- 02定义 API 契约与数据模型
- 03说明边界情况和错误处理
- 04描述 UX 流程与线框图
- 05促进产品、设计和工程协作
适用场景
- 01编写新产品功能规格
- 02记录 API 和数据需求
- 03详述复杂交互与工作流
- 04准备交付工程团队的文档
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ w95/ awesome-claude-corporate-skills --skill feature-spec安装后在 Claude Code 中输入/feature-spec确认已加载。
详细介绍
功能规格说明
概述
功能规格说明技能可帮助产品经理编写详细且可直接用于实施的功能规格说明,衔接设计与工程。它将功能需求、技术规格和用户体验流程整合为统一的信息源。
何时使用此技能
- 定义功能的技术需求
- 指定 API 契约和数据模型
- 记录边缘情况和错误处理方式
- 创建用户体验流程和线框图
- 确保设计与工程保持一致
- 为工程团队提供完整的规格说明
- 记录复杂的交互和工作流
功能规格说明模板
执行摘要
功能名称: [清晰且具有描述性的名称] 功能 ID: [唯一标识符] 负责人(PM): [姓名] 负责人(工程): [姓名] 状态: [草稿 / 审核中 / 已批准 / 开发中] 最后更新: [日期]
一句话描述: [用用户能理解的方式描述此功能的作用]
业务背景: [为何构建此功能、客户问题、业务目标]
关键指标: [衡量成功与否的方式]
功能需求
主要用例
用例 1:[名称]
- 参与者:[谁]
- 前置条件:[操作前的系统状态]
- 主流程:
- [步骤 1]
- [步骤 2]
- [步骤 3]
- 替代流程:
- [如果满足条件],则执行[步骤]
- 后置条件:[操作后的系统状态]
- 错误处理:[可能出现的问题]
详细功能规格
需求 1:实时更新
描述:团队成员更新任务后,所有正在查看该项目的其他团队成员都应在 2 秒内看到更新。
验收标准:
- 在 2 秒内向所有已连接的客户端广播更新
- 更新包含:任务 ID、新状态、旧状态、时间戳、执行更改的用户
- 广播使用 WebSocket(而非轮询)
- 支持不同设备和浏览器
- 离线用户重新连接后可收到更新
技术说明:
- 需要管理持久连接
- 妥善处理网络故障
- 向除发送者以外的所有人广播(避免回声)
需求 2:活动动态显示
描述:用户可以按时间倒序查看项目中的所有变更。
验收标准:
- 动态中显示所有活动(任务更新、评论、分配、状态变更)
- 按时间戳排序,最新的排在最前
- 每个条目显示:操作者、操作、目标对象、时间戳、上下文
- 初次加载动态时显示 20 个条目,更多内容通过分页加载
- 用户可以按以下条件筛选:活动类型、受派人、任务、日期范围
- 可以通过关键词搜索活动
技术说明:
- 使用分页,避免加载大量数据
- 将多个子事件合并为一项活动(将同一分钟内的更新分组)
- 将数据存储在活动表中,并使用反规范化字段提升性能
需求 3:通知送达
描述:发生与用户相关的活动时,用户会收到通知。
验收标准:
- 事件发生后 5 秒内向用户发送通知
- 通知包含:相关人员、执行的操作、对象、上下文链接
- 用户可以配置哪些活动类型会触发通知
- 用户可以选择送达方式:应用内、电子邮件、Slack、移动推送
- 用户可以设置免打扰时段(该时段内不发送通知)
- 对通知进行分组,以避免造成信息疲劳(每小时最多 1 封电子邮件)
技术说明:
- 不同通知渠道的延迟不同(电子邮件比应用内通知慢)
- 遵循用户的配置偏好
- 实现通知批处理
边缘情况和错误处理
错误场景
场景 1:更新状态时网络断开
- 用户在移动设备上更新任务状态
- 确认前网络断开
- 预期行为:
- UI 显示“待处理”状态
- 连接恢复后自动重试
- 3 次重试后仍失败则显示错误
- 允许手动重试
- 技术方案:
- 在本地对更新进行排队(IndexedDB)
- 连接恢复后同步
- 处理断开期间状态发生变化时的冲突
场景 2:重复的更新事件
- 同一更新收到两次(网络重试)
- 预期行为:
- 在客户端和服务端去重
- 活动动态中不出现重复条目
- 更新具备幂等性(重复应用也安全)
- 技术方案:
- 在更新中包含事件 ID
- 服务端处理前检查是否重复
- 即使已处理,也返回 200 OK
场景 3:对同一任务进行并发更新
- 两位用户同时更新同一任务
- 预期行为:
- 两项更新均生效(不采用最后写入者胜出)
- 不丢失数据
- 动态按顺序显示两项更新
- 不发生冲突或数据损坏
- 技术方案:
- 使用操作转换或无冲突副本
- 根据时间戳对动态排序
- 通过负载测试进行测试
场景 4:查看期间用户权限发生变化
- 用户正在查看项目时失去权限(被移出团队)
- 预期行为:
- 活动动态消失或显示错误消息
- 将用户重定向到可访问的页面
- 不泄露敏感数据
- 技术方案:
- 服务端在返回数据前检查权限
- 客户端妥善处理 403 Forbidden
- 显示清晰的错误消息
场景 5:超大型活动动态(1000+ 条)
- 项目有长达一年的活动历史记录
- 预期行为:
- 动态仍能快速加载
- 分页流畅
- 搜索性能可接受
- 技术方案:
- 为时间戳和筛选条件建立索引
- 优化数据库查询
- 在客户端使用虚拟滚动
数据模型规范
数据库架构
表:activities
CREATE TABLE activities (
id UUID PRIMARY KEY,
project_id UUID NOT NULL REFERENCES projects(id),
actor_id UUID NOT NULL REFERENCES users(id),
action_type VARCHAR(50) NOT NULL,
-- task_status_changed, task_comment_added, task_assigned, etc.
target_type VARCHAR(50) NOT NULL,
-- task, comment, assignment, project
target_id UUID NOT NULL,
-- ID of the object being changed
old_value JSONB,
-- Previous state (for updates): { "status": "todo" }
new_value JSONB,
-- New state: { "status": "done" }
metadata JSONB,
-- Extra context: { "duration_hours": 8, "effort_score": 5 }
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
CONSTRAINT check_values CHECK (
(old_value IS NOT NULL OR new_value IS NOT NULL)
)
);
CREATE INDEX idx_activities_project_created
ON activities(project_id, created_at DESC);
CREATE INDEX idx_activities_actor_created
ON activities(actor_id, created_at DESC);
表:notification_preferences
CREATE TABLE notification_preferences (
id UUID PRIMARY KEY,
user_id UUID NOT NULL UNIQUE REFERENCES users(id),
-- Activity type toggles
task_status_changed BOOLEAN DEFAULT true,
task_comment_added BOOLEAN DEFAULT true,
task_assigned_to_me BOOLEAN DEFAULT true,
-- Delivery method (can choose multiple)
email_enabled BOOLEAN DEFAULT true,
in_app_enabled BOOLEAN DEFAULT true,
slack_enabled BOOLEAN DEFAULT false,
mobile_push_enabled BOOLEAN DEFAULT true,
-- Do not disturb
dnd_enabled BOOLEAN DEFAULT false,
dnd_start TIME, -- 22:00
dnd_end TIME, -- 08:00
-- Batching
email_batch_frequency VARCHAR(20) DEFAULT 'hourly',
-- realtime, daily, weekly, never
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
表:activity_subscriptions
CREATE TABLE activity_subscriptions (
id UUID PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id),
resource_type VARCHAR(50) NOT NULL, -- task, project
resource_id UUID NOT NULL,
subscription_type VARCHAR(50) NOT NULL,
-- all_activities, mentions_only, assigned_only
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE UNIQUE INDEX idx_user_resource_subscription
ON activity_subscriptions(user_id, resource_type, resource_id);
数据字典
字段:action_type
- 类型:VARCHAR(50)
- 有效值:
- task_status_changed:任务状态已变更
- task_comment_added:已向任务添加评论
- task_assigned:任务已分配给用户
- task_unassigned:已取消将任务分配给用户
- task_description_updated:描述字段已修改
- task_due_date_changed:截止日期已修改
- task_priority_changed:优先级已修改
- project_created:项目已创建
- project_deleted:项目已删除
- team_member_added:已向项目添加团队成员
- team_member_removed:已从项目移除团队成员
字段:old_value 和 new_value
- 类型:JSONB
- 结构取决于 action_type
- 示例:
// For task_status_changed { "old": { "status": "todo" }, "new": { "status": "in_progress" } } // For task_comment_added { "new": { "comment_id": "abc123", "text": "This is a comment", "commenter": "Sarah" } } // For task_assigned { "new": { "assignee_id": "user123", "assignee_name": "John" } }
API 规范
端点:获取活动动态
请求:
GET /api/v1/projects/{projectId}/activities
Query parameters:
- limit: number (default: 20, max: 100)
- offset: number (default: 0)
- action_type: string (optional, filter)
- actor_id: string (optional, filter)
- start_date: ISO8601 (optional, filter)
- end_date: ISO8601 (optional, filter)
- search: string (optional, keyword search)
Headers:
- Authorization: Bearer {token}
响应(200 OK):
{
"data": [
{
"id": "activity-123",
"project_id": "proj-456",
"actor": {
"id": "user-789",
"name": "Sarah Chen",
"avatar_url": "https://..."
},
"action_type": "task_status_changed",
"action_label": "changed status",
"target": {
"type": "task",
"id": "task-999",
"name": "Build user auth",
"url": "/tasks/task-999"
},
"old_value": { "status": "todo" },
"new_value": { "status": "in_progress" },
"created_at": "2024-02-20T14:30:00Z",
"metadata": {
"duration_in_status": "2 days"
}
}
],
"pagination": {
"total": 250,
"offset": 0,
"limit": 20,
"has_more": true
}
}
响应(401 Unauthorized):
{
"error": "Unauthorized",
"message": "Authentication required"
}
响应(403 Forbidden):
{
"error": "Forbidden",
"message": "You don't have access to this project"
}
端点:更新任务状态(触发活动)
请求:
PATCH /api/v1/tasks/{taskId}
Body:
{
"status": "in_progress"
}
Headers:
- Authorization: Bearer {token}
- Content-Type: application/json
响应(200 OK):
{
"id": "task-999",
"name": "Build user auth",
"status": "in_progress",
"updated_at": "2024-02-20T14:30:00Z",
"activity_id": "activity-123"
}
自动创建的活动:
- action_type:task_status_changed
- old_value:{ "status": "todo" }
- new_value:{ "status": "in_progress" }
端点:更新通知偏好设置
请求:
PUT /api/v1/notifications/preferences
Body:
{
"email_enabled": true,
"in_app_enabled": true,
"slack_enabled": false,
"mobile_push_enabled": true,
"email_batch_frequency": "hourly",
"dnd_enabled": true,
"dnd_start": "22:00",
"dnd_end": "08:00"
}
响应(200 OK):
{
"id": "pref-123",
"user_id": "user-789",
"email_enabled": true,
"in_app_enabled": true,
"slack_enabled": false,
"mobile_push_enabled": true,
"updated_at": "2024-02-20T14:30:00Z"
}
WebSocket:实时活动广播
连接:
WS /api/v1/ws?token={token}&project_id={projectId}
订阅项目活动:
{
"type": "subscribe",
"project_id": "proj-456"
}
接收活动(广播):
{
"type": "activity_created",
"data": {
"id": "activity-123",
"project_id": "proj-456",
"action_type": "task_status_changed",
"actor": { "id": "user-789", "name": "Sarah Chen" },
"target": { "type": "task", "id": "task-999", "name": "Build user auth" },
"new_value": { "status": "in_progress" },
"created_at": "2024-02-20T14:30:00Z"
}
}
用户体验流程
流程 1:查看活动动态
屏幕 1:活动动态列表
┌─────────────────────────────────────┐
│ Activity Feed │
├─────────────────────────────────────┤
│ [Filter ▼] [Search _______________] │
├─────────────────────────────────────┤
│ Sarah Chen changed status │
│ "Build auth" → in progress │
│ 2 hours ago │
│ │
│ John Lee added comment │
│ "Build auth" - "Great progress" │
│ 3 hours ago │
│ │
│ Project created "Mobile App" │
│ by Jane Doe │
│ Yesterday │
│ │
│ [Load more] │
└─────────────────────────────────────┘
交互:
- 点击活动 → 导航到任务/对象
- 点击筛选器 → 显示选项(类型、日期、负责人)
- 在搜索框中输入 → 按关键词筛选
- 滚动到底部 → 加载更多条目
- 实时更新:新活动显示在顶部
流程 2:更新任务状态(触发活动)
当前状态: 任务状态为“todo”
用户操作: 点击任务,将状态下拉菜单更改为“in_progress”
系统行为:
- 调用 API 更新任务(PATCH /api/v1/tasks/{id})
- 服务器更新任务状态
- 服务器自动创建活动记录
- 服务器通过 WebSocket 广播活动
- 客户端接收广播
- 活动实时显示在所有已连接用户的动态流中
- UI 显示乐观更新(状态立即更改)
流程 3:配置通知
屏幕:通知设置模态框
┌──────────────────────────────────────┐
│ Notification Preferences │
├──────────────────────────────────────┤
│ Activity Types │
│ ☑ Task status changed │
│ ☑ Task assigned to me │
│ ☑ New comments │
│ ☐ Task description updated │
│ │
│ Delivery Methods │
│ ☑ Email │
│ ☑ In-app │
│ ☐ Slack │
│ ☑ Mobile push │
│ │
│ Email Settings │
│ Batch frequency: [Hourly ▼] │
│ │
│ Do Not Disturb │
│ ☑ Enabled │
│ From: [22:00] To: [08:00] │
│ │
│ [Save] [Cancel] │
└──────────────────────────────────────┘
性能要求
响应时间目标
| 操作 | 目标 | 可接受 | 不可接受 |
|---|---|---|---|
| 获取活动动态流 | 500ms | 1s | >2s |
| 实时广播 | 2s | 3s | >5s |
| 更新任务状态 | 1s | 2s | >3s |
| 搜索活动 | 1s | 2s | >3s |
| 加载通知设置 | 500ms | 1s | >2s |
可扩展性要求
- 每台服务器支持 10,000 个并发 WebSocket 连接
- 每分钟处理 1,000 条新建活动
- 包含 100,000+ 条记录的活动动态流必须在 <2 秒内加载
- p95 时数据库查询必须在 <500ms 内返回
数据量估算
- 活动表:约 100M 行(1 年的数据)
- 通知偏好设置:1M 行(每位用户 1 行)
- 每日新建活动:50K - 500K(取决于使用情况)
验收标准
- 已实现所有功能要求
- 已满足并测试所有验收标准
- 已妥善处理所有边缘情况
- 已测试所有错误场景
- 已达到性能目标(p95 延迟)
- 已通过负载测试验证可扩展性
- 已完成安全审查
- 已验证数据一致性
- 文档齐全
- QA 测试已通过
- 已获得产品经理签字确认
- 已准备好发布
交付成果
- 功能规格说明文档 - 完整规格说明(20-30 页)
- 数据模型图 - 模式可视化
- API 文档 - OpenAPI/Swagger 定义
- UX 流程图 - 每项功能的用户旅程
- 线框图 - 每个屏幕的 UI 模型图
- 错误处理指南 - 边缘情况和响应
- 性能基线 - 负载测试结果
- 实现检查清单 - 工程师交接文档