name: firebase-development-add-feature description: 此技能应用于向现有Firebase项目添加新功能。触发词包括“添加函数”、“创建端点”、“新工具”、“添加API”、“新集合”、“实现”、“构建功能”。指导采用测试驱动开发(TDD)工作流,包括测试先行、安全规则和模拟器验证。
Firebase 添加功能
概述
此子技能指导使用TDD方法向现有Firebase项目添加新功能。它处理云函数、Firestore集合和API端点。
核心原则:
- 首先编写测试(TDD要求)
- 使用
{success, message, data?}响应模式 - 所有文件以ABOUTME注释开头
- 在声明完成前使用模拟器验证
适用场景
- 添加新的云函数
- 创建带有规则的新Firestore集合
- 向Express应用添加API端点
- 用户提及:“添加函数”、“创建端点”、“新集合”、“实现”
不适用于:
- 初始项目设置 →
firebase-development:project-setup - 调试 →
firebase-development:debug - 代码审查 →
firebase-development:validate
TodoWrite 工作流
创建包含以下12个步骤的清单:
步骤 1: 识别功能类型
确定要添加的内容:
- HTTP端点 - API路由(GET/POST等)
- Firestore触发器 - 在文档变更时运行
- 计划函数 - 定时任务
- 可调用函数 - 客户端SDK调用
- 新集合 - 带有规则的Firestore集合
步骤 2: 检查现有架构
检查项目以了解现有模式:
ls -la functions/src/
grep -r "onRequest" functions/src/
grep "express" functions/package.json
确定: 架构风格、认证方法、安全模型。
参考: docs/examples/express-function-architecture.md
步骤 3: 首先编写失败的测试(TDD)
在实现之前创建测试文件:
// ABOUTME: [功能名称] 功能的单元测试
// ABOUTME: 测试[功能描述]的各种场景
import { describe, it, expect } from 'vitest';
import { handleYourFeature } from '../../tools/yourFeature';
describe('handleYourFeature', () => {
it('给定有效输入时应返回成功', async () => {
const result = await handleYourFeature('user-123', { name: 'test' });
expect(result.success).toBe(true);
});
it('对于无效输入应返回错误', async () => {
const result = await handleYourFeature('user-123', { name: '' });
expect(result.success).toBe(false);
});
});
运行测试以确认失败:npm run test
步骤 4: 创建带有ABOUTME的函数文件
创建实现文件:
// ABOUTME: 实现[功能名称],用于[目的]
// ABOUTME: 返回 {success, message, data?} 响应
export async function handleYourFeature(
userId: string,
params: { name: string }
): Promise<{ success: boolean; message: string; data?: any }> {
if (!userId) {
return { success: false, message: '需要身份验证' };
}
if (!params.name) {
return { success: false, message: '无效输入:需要名称' };
}
// 在此处实现
return { success: true, message: '成功', data: { /* ... */ } };
}
参考: docs/examples/express-function-architecture.md
步骤 5: 添加Firestore安全规则
为新集合更新 firestore.rules:
仅服务器写入(推荐):
match /yourCollection/{docId} {
allow read: if request.auth != null;
allow write: if false; // 仅限云函数
}
客户端写入(如需要):
match /yourCollection/{docId} {
allow create: if request.auth != null &&
request.resource.data.userId == request.auth.uid;
allow update: if request.auth != null &&
resource.data.userId == request.auth.uid &&
request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['name', 'updatedAt']);
}
参考: docs/examples/firestore-rules-patterns.md
步骤 6: 如需要则更新索引
为复杂查询添加到 firestore.indexes.json:
{
"collectionGroup": "yourCollection",
"fields": [
{"fieldPath": "userId", "order": "ASCENDING"},
{"fieldPath": "createdAt", "order": "DESCENDING"}
]
}
如无复杂查询(单字段索引自动创建)可跳过。
步骤 7: 添加身份验证检查
基于项目模式:
API密钥:
app.post('/endpoint', apiKeyGuard, async (req, res) => {
const userId = req.userId!;
// ...
});
Firebase Auth:
if (!req.auth) {
res.status(401).json({ success: false, message: '需要身份验证' });
return;
}
const userId = req.auth.uid;
参考: docs/examples/api-key-authentication.md
步骤 8: 使用响应模式实现处理器
所有处理器使用一致的模式:
interface HandlerResponse {
success: boolean;
message: string;
data?: any;
}
在每一层都包含验证(深度防御)。
步骤 9: 正确导出函数
添加到 functions/src/index.ts:
Express: 添加路由或switch case
按域分组: export * from './yourDomain';
单独导出: 在index.js中导入并导出
验证:npm run build
步骤 10: 使测试通过(TDD 绿灯)
运行测试:npm run test
所有测试应通过。如未通过,修复实现(而非测试)。
步骤 11: 编写集成测试
创建 functions/src/__tests__/emulator/yourFeature.test.ts:
使用模拟器测试完整工作流:
- 向端点发送HTTP请求
- 验证Firestore数据创建
- 测试身份验证强制执行
运行:npm run test:emulator(需运行模拟器)
步骤 12: 使用模拟器测试
firebase emulators:start
open http://127.0.0.1:4000
验证:
- 端点返回200
- 响应遵循模式
- 文档出现在Firestore中
- 身份验证强制执行(无效请求返回401)
- 规则在Rules Playground中工作
响应模式
所有处理器必须返回:
// 成功
{ success: true, message: "已创建", data: { id: "abc" } }
// 错误
{ success: false, message: "无效输入" }
验证清单
在标记完成前:
- [ ] 测试已首先编写并通过
- [ ] 所有文件都有ABOUTME注释
- [ ] 安全规则已添加
- [ ] 身份验证检查已实现
- [ ] 响应模式已遵循
- [ ] 模拟器测试成功
- [ ] 代码已通过lint检查
模式参考
- 架构:
docs/examples/express-function-architecture.md - 身份验证:
docs/examples/api-key-authentication.md - 规则:
docs/examples/firestore-rules-patterns.md - 模拟器:
docs/examples/emulator-workflow.md