Initial commit
This commit is contained in:
@@ -0,0 +1,501 @@
|
||||
# Feature Development Handoff Example
|
||||
|
||||
Complete multi-agent workflow for feature development with context handoffs.
|
||||
|
||||
**Workflow**: Design → Implement → Test → Deploy
|
||||
**Duration**: 4-6 hours
|
||||
**Agents**: 4 (backend-architect, tdd-typescript, test-generator, devops-troubleshooter)
|
||||
**Context Handoffs**: 3
|
||||
|
||||
---
|
||||
|
||||
## Workflow Overview
|
||||
|
||||
```
|
||||
User Request → Backend Architect → TDD TypeScript → Test Generator → DevOps Deploy
|
||||
↓ save ↓ save ↓ save ↓
|
||||
context-1 context-2 context-3 ✅ Complete
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Architecture Design
|
||||
|
||||
**Agent**: `backend-architect`
|
||||
**Goal**: Design API endpoints and data model
|
||||
|
||||
**User Input**:
|
||||
"Add user preferences feature: users can save theme (light/dark), language (en/es/fr), and notification settings (email, push)."
|
||||
|
||||
**Agent Work**:
|
||||
1. Analyzes requirements
|
||||
2. Designs database schema
|
||||
3. Plans API endpoints
|
||||
4. Creates OpenAPI spec
|
||||
|
||||
**Output**:
|
||||
```typescript
|
||||
// Designed schema
|
||||
interface UserPreferences {
|
||||
user_id: string;
|
||||
theme: 'light' | 'dark';
|
||||
language: 'en' | 'es' | 'fr';
|
||||
notifications: {
|
||||
email: boolean;
|
||||
push: boolean;
|
||||
};
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
// Planned endpoints
|
||||
GET /api/v1/users/:id/preferences
|
||||
PUT /api/v1/users/:id/preferences
|
||||
PATCH /api/v1/users/:id/preferences
|
||||
```
|
||||
|
||||
**Decisions Made**:
|
||||
- Use JSONB column in PostgreSQL for preferences (flexibility)
|
||||
- PUT for full replace, PATCH for partial update
|
||||
- Include updated_at for conflict resolution
|
||||
- Rate limit: 10 requests/minute per user
|
||||
|
||||
**Context Save** (`context-001-design.json`):
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"workflow_id": "feature-user-prefs-20250115",
|
||||
"timestamp": "2025-01-15T10:30:00Z",
|
||||
"current_agent": "backend-architect",
|
||||
"next_agent": "tdd-typescript",
|
||||
"phase": "design-complete",
|
||||
|
||||
"files_modified": [
|
||||
"docs/api/user-preferences.md",
|
||||
"docs/architecture/decisions/adr-012-user-prefs-storage.md"
|
||||
],
|
||||
|
||||
"decisions": [
|
||||
"Use JSONB for flexibility in preferences structure",
|
||||
"Implement both PUT (full) and PATCH (partial) updates",
|
||||
"Rate limit to 10 req/min per user to prevent abuse",
|
||||
"Include updated_at for optimistic locking"
|
||||
],
|
||||
|
||||
"data_model": {
|
||||
"table": "user_preferences",
|
||||
"columns": {
|
||||
"id": "UUID PRIMARY KEY",
|
||||
"user_id": "UUID REFERENCES users(id)",
|
||||
"preferences": "JSONB NOT NULL",
|
||||
"created_at": "TIMESTAMP DEFAULT NOW()",
|
||||
"updated_at": "TIMESTAMP DEFAULT NOW()"
|
||||
},
|
||||
"indexes": [
|
||||
"user_id (unique)",
|
||||
"updated_at"
|
||||
]
|
||||
},
|
||||
|
||||
"api_spec": {
|
||||
"endpoints": [
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/api/v1/users/:id/preferences",
|
||||
"auth_required": true,
|
||||
"rate_limit": "10/minute",
|
||||
"response": "UserPreferences"
|
||||
},
|
||||
{
|
||||
"method": "PUT",
|
||||
"path": "/api/v1/users/:id/preferences",
|
||||
"auth_required": true,
|
||||
"body": "UserPreferencesUpdate",
|
||||
"response": "UserPreferences"
|
||||
},
|
||||
{
|
||||
"method": "PATCH",
|
||||
"path": "/api/v1/users/:id/preferences",
|
||||
"auth_required": true,
|
||||
"body": "Partial<UserPreferencesUpdate>",
|
||||
"response": "UserPreferences"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"pending_actions": [
|
||||
"Implement API endpoints with TDD approach",
|
||||
"Create database migration",
|
||||
"Add validation for preference values",
|
||||
"Implement rate limiting middleware"
|
||||
],
|
||||
|
||||
"constraints": [
|
||||
"Must maintain backward compatibility",
|
||||
"Performance: GET should be < 50ms",
|
||||
"Must handle concurrent updates (optimistic locking)"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Handoff Message**:
|
||||
"Design complete. Data model uses JSONB for flexibility. Three endpoints designed (GET/PUT/PATCH). Ready for TDD implementation. Key constraints: < 50ms response, handle concurrency, rate limiting."
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: TDD Implementation
|
||||
|
||||
**Agent**: `tdd-typescript-implementer`
|
||||
**Goal**: Implement API endpoints following TDD
|
||||
|
||||
**Context Restore**:
|
||||
```typescript
|
||||
// Agent loads context-001-design.json
|
||||
const context = await loadContext('feature-user-prefs-20250115');
|
||||
|
||||
console.log('Previous agent:', context.current_agent);
|
||||
console.log('Decisions:', context.decisions);
|
||||
console.log('Next steps:', context.pending_actions);
|
||||
console.log('Constraints:', context.constraints);
|
||||
```
|
||||
|
||||
**Agent Work**:
|
||||
Following RED-GREEN-REFACTOR cycle:
|
||||
|
||||
**Cycle 1**: GET /preferences endpoint
|
||||
```typescript
|
||||
// RED: Write failing test
|
||||
describe('GET /api/v1/users/:id/preferences', () => {
|
||||
it('returns user preferences', async () => {
|
||||
const response = await request(app)
|
||||
.get('/api/v1/users/user-123/preferences')
|
||||
.set('Authorization', 'Bearer token');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toMatchObject({
|
||||
user_id: 'user-123',
|
||||
theme: 'light',
|
||||
language: 'en'
|
||||
});
|
||||
});
|
||||
});
|
||||
// ❌ Test fails - endpoint doesn't exist
|
||||
|
||||
// GREEN: Minimal implementation
|
||||
router.get('/users/:id/preferences', authenticate, async (req, res) => {
|
||||
const prefs = await db.getUserPreferences(req.params.id);
|
||||
res.json(prefs);
|
||||
});
|
||||
// ✅ Test passes
|
||||
|
||||
// REFACTOR: Add caching, validation
|
||||
router.get('/users/:id/preferences',
|
||||
authenticate,
|
||||
validateUserId,
|
||||
cacheMiddleware({ ttl: 300 }),
|
||||
async (req, res) => {
|
||||
const prefs = await db.getUserPreferences(req.params.id);
|
||||
res.json(prefs);
|
||||
}
|
||||
);
|
||||
// ✅ All tests still pass
|
||||
```
|
||||
|
||||
**Cycle 2-4**: PUT and PATCH endpoints (similar process)
|
||||
|
||||
**Context Save** (`context-002-implementation.json`):
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"workflow_id": "feature-user-prefs-20250115",
|
||||
"timestamp": "2025-01-15T14:45:00Z",
|
||||
"current_agent": "tdd-typescript",
|
||||
"next_agent": "test-generator",
|
||||
"phase": "implementation-complete",
|
||||
|
||||
"files_modified": [
|
||||
"src/api/routes/user-preferences.ts",
|
||||
"src/api/middleware/rate-limit.ts",
|
||||
"src/db/repositories/preferences.ts",
|
||||
"src/types/user-preferences.ts",
|
||||
"migrations/2025-01-15-user-preferences.sql"
|
||||
],
|
||||
|
||||
"test_results": {
|
||||
"total": 18,
|
||||
"passing": 18,
|
||||
"failing": 0,
|
||||
"coverage": {
|
||||
"line": 96,
|
||||
"branch": 94,
|
||||
"function": 100
|
||||
}
|
||||
},
|
||||
|
||||
"decisions": [
|
||||
"Added caching (5min TTL) for GET endpoint",
|
||||
"Implemented optimistic locking with updated_at",
|
||||
"Used Zod for runtime validation",
|
||||
"Rate limiting uses Redis for distributed systems"
|
||||
],
|
||||
|
||||
"pending_actions": [
|
||||
"Generate comprehensive integration tests",
|
||||
"Add E2E tests for full user flows",
|
||||
"Test edge cases (concurrent updates, invalid data)",
|
||||
"Performance testing under load"
|
||||
],
|
||||
|
||||
"metrics": {
|
||||
"implementation_time": "3.5 hours",
|
||||
"test_count": 18,
|
||||
"code_loc": 420,
|
||||
"test_loc": 580
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Handoff Message**:
|
||||
"Implementation complete with 18 passing tests, 96% coverage. All three endpoints functional. Caching, validation, rate limiting implemented. Ready for comprehensive testing."
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Test Generation
|
||||
|
||||
**Agent**: `test-generator`
|
||||
**Goal**: Create comprehensive test suite
|
||||
|
||||
**Context Restore**:
|
||||
```typescript
|
||||
const context = await loadContext('feature-user-prefs-20250115');
|
||||
const implementedFiles = context.files_modified;
|
||||
const coverageGaps = identifyGaps(context.test_results.coverage);
|
||||
```
|
||||
|
||||
**Agent Work**:
|
||||
1. Analyzes implementation
|
||||
2. Identifies uncovered branches
|
||||
3. Generates integration tests
|
||||
4. Creates E2E test scenarios
|
||||
|
||||
**Generated Tests**:
|
||||
|
||||
**Integration Test**:
|
||||
```typescript
|
||||
describe('User Preferences Integration', () => {
|
||||
it('handles concurrent updates correctly', async () => {
|
||||
const userId = 'user-123';
|
||||
|
||||
// Simulate two clients updating simultaneously
|
||||
const [update1, update2] = await Promise.allSettled([
|
||||
api.updatePreferences(userId, { theme: 'dark' }),
|
||||
api.updatePreferences(userId, { language: 'es' })
|
||||
]);
|
||||
|
||||
// One should succeed, one should get conflict (409)
|
||||
const statuses = [update1.status, update2.status].sort();
|
||||
expect(statuses).toEqual([200, 409]);
|
||||
|
||||
// Final state should be consistent
|
||||
const final = await api.getPreferences(userId);
|
||||
expect(final.theme === 'dark' || final.language === 'es').toBe(true);
|
||||
});
|
||||
|
||||
it('respects rate limits', async () => {
|
||||
const requests = Array(15).fill(null).map(() =>
|
||||
api.updatePreferences('user-123', { theme: 'dark' })
|
||||
);
|
||||
|
||||
const results = await Promise.allSettled(requests);
|
||||
const rateLimited = results.filter(r => r.status === 429);
|
||||
|
||||
expect(rateLimited.length).toBeGreaterThan(0); // Some rejected
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Context Save** (`context-003-testing.json`):
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"workflow_id": "feature-user-prefs-20250115",
|
||||
"timestamp": "2025-01-15T16:30:00Z",
|
||||
"current_agent": "test-generator",
|
||||
"next_agent": "devops-troubleshooter",
|
||||
"phase": "testing-complete",
|
||||
|
||||
"files_modified": [
|
||||
"tests/integration/user-preferences.test.ts",
|
||||
"tests/e2e/preferences-flow.test.ts",
|
||||
"tests/performance/preferences-load.test.ts"
|
||||
],
|
||||
|
||||
"test_results": {
|
||||
"unit": { "total": 18, "passing": 18 },
|
||||
"integration": { "total": 12, "passing": 12 },
|
||||
"e2e": { "total": 5, "passing": 5 },
|
||||
"performance": {
|
||||
"avg_response_time": "42ms",
|
||||
"p95_response_time": "68ms",
|
||||
"p99_response_time": "95ms",
|
||||
"throughput": "450 req/sec"
|
||||
}
|
||||
},
|
||||
|
||||
"final_coverage": {
|
||||
"line": 98,
|
||||
"branch": 97,
|
||||
"function": 100
|
||||
},
|
||||
|
||||
"pending_actions": [
|
||||
"Deploy to staging environment",
|
||||
"Run smoke tests in staging",
|
||||
"Monitor error rates and performance",
|
||||
"Deploy to production with canary"
|
||||
],
|
||||
|
||||
"quality_gates_passed": {
|
||||
"coverage": true,
|
||||
"performance": true,
|
||||
"security": true,
|
||||
"accessibility": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Handoff Message**:
|
||||
"Testing complete. 35 tests total, all passing. 98% coverage. Performance within targets (< 50ms avg). Ready for deployment."
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Deployment
|
||||
|
||||
**Agent**: `devops-troubleshooter`
|
||||
**Goal**: Deploy to staging and production
|
||||
|
||||
**Context Restore**:
|
||||
```typescript
|
||||
const context = await loadContext('feature-user-prefs-20250115');
|
||||
const performanceMetrics = context.test_results.performance;
|
||||
const qualityGates = context.quality_gates_passed;
|
||||
|
||||
// Verify all gates passed
|
||||
if (!Object.values(qualityGates).every(passed => passed)) {
|
||||
throw new Error('Quality gates not met - cannot deploy');
|
||||
}
|
||||
```
|
||||
|
||||
**Agent Work**:
|
||||
1. Creates deployment pipeline
|
||||
2. Deploys to staging
|
||||
3. Runs smoke tests
|
||||
4. Deploys to production (canary)
|
||||
5. Monitors rollout
|
||||
|
||||
**Deployment Steps**:
|
||||
```yaml
|
||||
# .github/workflows/deploy-user-prefs.yml
|
||||
name: Deploy User Preferences Feature
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
environment:
|
||||
description: 'Environment'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- staging
|
||||
- production
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
steps:
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
|
||||
- name: Check coverage
|
||||
run: npm run coverage -- --threshold=95
|
||||
|
||||
- name: Deploy to staging
|
||||
if: inputs.environment == 'staging'
|
||||
run: |
|
||||
npx wrangler deploy --env staging
|
||||
npm run smoke-test:staging
|
||||
|
||||
- name: Deploy to production (canary)
|
||||
if: inputs.environment == 'production'
|
||||
run: |
|
||||
npx wrangler deploy --env production --percentage 10
|
||||
npm run monitor:canary
|
||||
|
||||
- name: Full rollout
|
||||
if: inputs.environment == 'production'
|
||||
run: npx wrangler deploy --env production --percentage 100
|
||||
```
|
||||
|
||||
**Final Context** (`context-004-complete.json`):
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"workflow_id": "feature-user-prefs-20250115",
|
||||
"timestamp": "2025-01-15T18:00:00Z",
|
||||
"current_agent": "devops-troubleshooter",
|
||||
"next_agent": null,
|
||||
"phase": "deployed",
|
||||
|
||||
"deployment": {
|
||||
"staging": {
|
||||
"deployed_at": "2025-01-15T17:15:00Z",
|
||||
"smoke_tests": "passed",
|
||||
"url": "https://staging.example.com"
|
||||
},
|
||||
"production": {
|
||||
"canary_started": "2025-01-15T17:45:00Z",
|
||||
"canary_percentage": 10,
|
||||
"full_rollout": "2025-01-15T17:55:00Z",
|
||||
"url": "https://api.example.com"
|
||||
}
|
||||
},
|
||||
|
||||
"monitoring": {
|
||||
"error_rate": "0.02%",
|
||||
"avg_latency": "38ms",
|
||||
"p99_latency": "89ms",
|
||||
"requests_served": 12500
|
||||
},
|
||||
|
||||
"status": "complete",
|
||||
"total_duration": "7.5 hours",
|
||||
"agents_involved": 4,
|
||||
"context_handoffs": 3
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Lessons Learned
|
||||
|
||||
**What Went Well**:
|
||||
- Clear context handoffs prevented re-work
|
||||
- Performance targets met from design phase
|
||||
- TDD approach caught issues early
|
||||
- Automated deployment smooth
|
||||
|
||||
**Improvements for Next Time**:
|
||||
- Could have parallelized testing and deployment prep
|
||||
- Context size grew large - could compress history
|
||||
- Should add rollback procedure to context
|
||||
|
||||
**Metrics**:
|
||||
- **Time saved** vs starting fresh each phase: ~40%
|
||||
- **Context restore success**: 100%
|
||||
- **Quality maintained** across all handoffs: Yes
|
||||
|
||||
---
|
||||
|
||||
**Total Workflow Time**: 7.5 hours
|
||||
**Agents Involved**: 4
|
||||
**Context Saves**: 4
|
||||
**Handoff Success Rate**: 100%
|
||||
**Final Quality**: Production-ready
|
||||
Reference in New Issue
Block a user