When a feature needs specifying, /product-specs-writer drafts the full PRD, so you can move straight to engineering review. — Claude Skill
A Claude Skill for Claude Code by Nick Jensen — run /product-specs-writer in Claude·Updated
Draft PRDs, user stories, acceptance criteria, and technical specs from a brief.
- Generates PRDs with goals, non-goals, milestones, and success metrics
- Breaks features into user stories with Gherkin acceptance criteria
- Produces edge case matrices covering error states and boundary conditions
- Drafts API endpoint specs with request/response schemas
- Creates feature flag rollout plans with percentage ramps and kill switches
Who this is for
What it does
Give /product-specs-writer a one-paragraph feature idea and get a structured PRD with problem statement, proposed solution, milestones, metrics, and open questions.
Paste your PRD into /product-specs-writer to get 8-15 user stories with acceptance criteria in Given/When/Then format, grouped by epic.
Run /product-specs-writer on a feature spec to produce a matrix of 20+ edge cases covering null inputs, rate limits, concurrent edits, and permission boundaries.
Describe your endpoints to /product-specs-writer and receive OpenAPI-style specs with request schemas, response examples, error codes, and auth requirements.
Feed /product-specs-writer your rollout context to get a staged flag plan: internal dogfood, 5% canary, 25% beta, 100% GA, with rollback triggers at each stage.
How it works
Provide a feature brief, existing doc, or product area you need specified.
The skill identifies which spec artifacts are needed — PRD, stories, acceptance criteria, API docs, or flag plans.
It generates each artifact with consistent cross-references, linking stories back to PRD goals and acceptance criteria to edge cases.
You review, add constraints or context, and re-run to refine until the spec is engineering-ready.
Example
Add a 'schedule send' feature to our email composer. Users pick a date/time, the email queues, and sends at that time. Support timezone selection and cancellation before send.
Users in distributed teams compose emails outside recipients' working hours. 34% of surveyed users requested delayed delivery to land in-inbox at optimal times.
US-1: As a composer, I want to pick a future date and time so my email arrives when the recipient is active. AC: Given I select a valid future datetime, when I click 'Schedule,' then the email moves to the Scheduled queue with status 'pending.' US-2: As a composer, I want to cancel a scheduled email before it sends so I can edit or discard it. AC: Given a scheduled email with status 'pending,' when I click 'Cancel,' then it returns to Drafts and the queue job is deleted.
1. User selects a time in the past → show inline error, keep modal open. 2. Timezone changes between scheduling and send time → use UTC internally, display in user's current tz. 3. Server downtime at scheduled time → retry 3x over 15 min, then notify user.
Works with
Product Specs Writer
Comprehensive product documentation expertise — from strategic PRDs to implementation-ready specifications that engineering teams can actually build from.
Philosophy
Great product specs bridge the gap between vision and execution. They're not bureaucratic documents; they're communication tools that align teams and prevent expensive misunderstandings.
The best product specifications:
- Start with the why — Context before requirements
- Are testable — Every requirement has clear acceptance criteria
- Anticipate questions — Edge cases, errors, and constraints documented upfront
- Evolve with the product — Living documents, not static artifacts
- Respect the reader — Engineers, designers, and stakeholders can all understand them
How This Skill Works
When invoked, apply the guidelines in rules/ organized by:
prd-*— Product Requirements Documents, vision, scopestories-*— User stories, personas, jobs-to-be-donecriteria-*— Acceptance criteria, definition of donetechnical-*— Technical specifications, architecture decisionsapi-*— API specifications, contracts, versioningedge-*— Edge cases, error handling, failure modesdesign-*— Design handoff, component specs, interactionsrollout-*— Feature flags, rollout plans, experimentsmetrics-*— Success metrics, KPIs, measurement plansmaintenance-*— Documentation lifecycle, versioning, deprecation
Core Frameworks
Specification Hierarchy
┌─────────────────────────────────────────┐
│ VISION │ ← Why are we building this?
│ (Problem & Opportunity) │
├─────────────────────────────────────────┤
│ PRD │ ← What are we building?
│ (Requirements & Constraints) │
├─────────────────────────────────────────┤
│ USER STORIES │ ← Who benefits and how?
│ (Personas & Journeys) │
├─────────────────────────────────────────┤
│ ACCEPTANCE CRITERIA │ ← How do we know it's done?
│ (Testable Conditions) │
├─────────────────────────────────────────┤
│ TECHNICAL SPECS │ ← How do we build it?
│ (Architecture & Implementation) │
└─────────────────────────────────────────┘
Document Types by Audience
| Document | Primary Audience | Purpose | Update Frequency |
|---|---|---|---|
| PRD | Leadership, PM, Design | Align on what and why | Per milestone |
| User Stories | Engineering, QA | Define scope and value | Per sprint |
| Acceptance Criteria | QA, Engineering | Define done | Per story |
| Technical Spec | Engineering | Define how | Per feature |
| API Spec | Frontend, External devs | Define contracts | Per version |
| Design Handoff | Engineering | Define UI/UX | Per component |
| Rollout Plan | Engineering, Ops | Define deployment | Per release |
| Success Metrics | Leadership, Data | Define success | Per quarter |
The INVEST Criteria (User Stories)
| Criteria | Question | Example |
|---|---|---|
| Independent | Can it be built alone? | No dependencies on unfinished stories |
| Negotiable | Is scope flexible? | Details can be refined with engineering |
| Valuable | Does user benefit? | Clear value proposition stated |
| Estimable | Can we size it? | Enough detail to estimate effort |
| Small | Fits in a sprint? | Can be completed in 1-5 days |
| Testable | Can we verify it? | Has clear acceptance criteria |
Specification Completeness Checklist
PRD Completeness:
├── Problem Statement □ Clearly defined user pain
├── Success Metrics □ Measurable outcomes defined
├── User Stories □ All personas covered
├── Scope □ In-scope and out-of-scope clear
├── Constraints □ Technical and business limits stated
├── Dependencies □ External dependencies identified
├── Risks □ Known risks and mitigations
├── Timeline □ Milestones and deadlines set
└── Open Questions □ Unknowns explicitly listed
Technical Spec Completeness:
├── Architecture □ System design documented
├── Data Model □ Schema and relationships defined
├── API Contracts □ Endpoints and payloads specified
├── Edge Cases □ Failure modes documented
├── Security □ Auth, encryption, compliance covered
├── Performance □ SLAs and benchmarks defined
├── Monitoring □ Observability strategy clear
└── Rollback Plan □ Recovery procedures documented
Error Handling Taxonomy
| Error Type | Example | Documentation Required |
|---|---|---|
| Validation | Invalid email format | Error message, field highlighting |
| Authorization | User lacks permission | Error state, escalation path |
| Resource | Item not found | Empty state, recovery action |
| System | Database timeout | Retry strategy, user feedback |
| Business Logic | Insufficient balance | Error explanation, next steps |
| External | Third-party API down | Fallback behavior, degraded mode |
Specification Templates
Minimal PRD Structure
# Feature: [Name]
## Problem
What user problem are we solving?
## Solution
High-level approach (1-2 paragraphs)
## Success Metrics
- Primary: [Metric] from X to Y
- Secondary: [Metric] from X to Y
## User Stories
- As a [user], I want [goal] so that [benefit]
## Scope
**In scope:** [List]
**Out of scope:** [List]
## Open Questions
- [ ] Question 1
- [ ] Question 2
User Story Template
**As a** [persona/user type]
**I want** [capability/action]
**So that** [benefit/value]
**Acceptance Criteria:**
- Given [context], when [action], then [result]
- Given [context], when [action], then [result]
**Edge Cases:**
- What if [edge case]? Then [behavior]
**Out of Scope:**
- [Explicit exclusion]
Anti-Patterns
- Spec by committee — Over-collaboration produces vague documents
- Premature optimization — Specifying implementation details too early
- Missing the why — Requirements without context for decisions
- Kitchen sink scope — Trying to solve everything in one release
- One-way documentation — Specs that don't get updated as learnings emerge
- Assumption blindness — Not documenting implicit assumptions
- Designer/Engineer telephone — No direct communication, only docs
- Success theater — Metrics chosen because they're easy, not meaningful
- Spec as contract — Treating specs as unchangeable legal documents
- Documentation debt — Outdated specs worse than no specs
Reference documents
title: Section Organization
1. PRD Writing (prd)
Impact: CRITICAL Description: Product Requirements Documents that align stakeholders on vision, scope, and success criteria. The foundation for all downstream specifications.
2. User Stories (stories)
Impact: CRITICAL Description: User-centric requirements that capture who benefits, what they need, and why it matters. The bridge between business goals and engineering work.
3. Acceptance Criteria (criteria)
Impact: CRITICAL Description: Testable conditions that define when a story is complete. The contract between PM, engineering, and QA.
4. Technical Specifications (technical)
Impact: HIGH Description: Architecture decisions, system design, and implementation guidance. How the solution will be built.
5. API Specifications (api)
Impact: HIGH Description: API contracts, request/response formats, versioning, and documentation. The interface between systems and teams.
6. Edge Cases & Error Handling (edge)
Impact: HIGH Description: Failure modes, error states, and exception handling. What happens when things go wrong.
7. Design Handoff (design)
Impact: MEDIUM-HIGH Description: Component specifications, interaction states, and responsive requirements. Translating designs to implementation.
8. Feature Flags & Rollout (rollout)
Impact: MEDIUM-HIGH Description: Progressive rollout strategies, feature flags, experiments, and kill switches. Safe deployment patterns.
9. Success Metrics (metrics)
Impact: HIGH Description: KPIs, measurement plans, and success criteria. How we know if we built the right thing.
10. Documentation Maintenance (maintenance)
Impact: MEDIUM Description: Documentation lifecycle, versioning, deprecation, and update workflows. Keeping specs accurate over time.
title: API Specifications impact: HIGH tags: api, rest, openapi, documentation, contracts
API Specifications
Impact: HIGH
API specs are contracts between services, teams, and external developers. Clear specs prevent integration bugs, reduce back-and-forth, and enable parallel development of frontend and backend.
API Design Principles
- Consistency — Same patterns across all endpoints
- Predictability — Developers can guess behavior
- Discoverability — Self-documenting responses
- Evolvability — Can change without breaking clients
- Debuggability — Errors help developers fix issues
API Specification Components
| Component | Purpose | Required |
|---|---|---|
| Endpoint | URL path and HTTP method | Yes |
| Description | What this endpoint does | Yes |
| Authentication | Auth requirements | Yes |
| Request | Headers, params, body | Yes |
| Response | Success and error formats | Yes |
| Examples | Real request/response samples | Yes |
| Rate Limits | Throttling rules | If applicable |
| Versioning | API version info | Yes |
Good API Spec Example (OpenAPI Style)
# POST /workspaces/{workspace_id}/invitations
# Create a new workspace invitation
summary: Invite a user to a workspace
description: |
Sends an invitation email to the specified address. The recipient
can accept the invitation to join the workspace with the specified
permission level. Invitations expire after 7 days.
Requires Owner permission on the workspace.
tags:
- Workspace Sharing
security:
- BearerAuth: []
parameters:
- name: workspace_id
in: path
required: true
description: The unique identifier of the workspace
schema:
type: string
format: uuid
example: "550e8400-e29b-41d4-a716-446655440000"
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
- permission_level
properties:
email:
type: string
format: email
description: Email address of the person to invite
example: "[email protected]"
permission_level:
type: string
enum: [viewer, editor, owner]
description: Permission level to grant
example: "editor"
message:
type: string
maxLength: 500
description: Optional personal message to include in email
example: "Welcome to the team! Check out our Q4 planning workspace."
responses:
201:
description: Invitation created successfully
content:
application/json:
schema:
type: object
properties:
id:
type: string
format: uuid
workspace_id:
type: string
format: uuid
email:
type: string
permission_level:
type: string
invited_by:
type: string
format: uuid
expires_at:
type: string
format: date-time
created_at:
type: string
format: date-time
example:
id: "d290f1ee-6c54-4b01-90e6-d701748f0851"
workspace_id: "550e8400-e29b-41d4-a716-446655440000"
email: "[email protected]"
permission_level: "editor"
invited_by: "7c9e6679-7425-40de-944b-e07fc1f90ae7"
expires_at: "2024-01-22T10:30:00Z"
created_at: "2024-01-15T10:30:00Z"
400:
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
invalid_email:
summary: Invalid email format
value:
error:
code: "INVALID_EMAIL"
message: "The email address format is invalid"
field: "email"
workspace_full:
summary: Workspace at member limit
value:
error:
code: "WORKSPACE_FULL"
message: "This workspace has reached its member limit (50)"
limit: 50
current: 50
401:
description: Authentication required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: "UNAUTHORIZED"
message: "Authentication token is missing or invalid"
403:
description: Permission denied
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: "FORBIDDEN"
message: "Only workspace owners can send invitations"
required_permission: "owner"
your_permission: "editor"
404:
description: Workspace not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: "WORKSPACE_NOT_FOUND"
message: "Workspace with ID '550e8400-...' does not exist"
409:
description: Conflict - user already invited or member
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
already_member:
summary: User is already a member
value:
error:
code: "ALREADY_MEMBER"
message: "This user is already a workspace member"
existing_permission: "editor"
pending_invitation:
summary: Invitation already pending
value:
error:
code: "INVITATION_PENDING"
message: "An invitation is already pending for this email"
invitation_id: "d290f1ee-6c54-4b01-90e6-d701748f0851"
expires_at: "2024-01-22T10:30:00Z"
429:
description: Rate limit exceeded
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: "RATE_LIMITED"
message: "Invitation limit exceeded. Try again later."
retry_after: 3600
headers:
Retry-After:
description: Seconds until rate limit resets
schema:
type: integer
example: 3600
x-rate-limit:
requests: 10
window: 3600
scope: workspace
x-changelog:
- version: "2024-01-15"
changes:
- Added optional message field
- version: "2023-11-01"
changes:
- Initial release
Bad API Spec Example
# POST /invite
# Invite user
request:
email: string
level: string
response:
success: boolean
Why it fails:
- No endpoint description
- No authentication documented
- No parameter details or constraints
- Missing error responses
- No examples
- No versioning information
- Vague response schema
Error Response Standards
Consistent Error Schema:
{
"error": {
"code": "MACHINE_READABLE_CODE",
"message": "Human readable explanation",
"details": {
"field": "problematic_field",
"reason": "Specific validation failure"
},
"request_id": "req_abc123",
"documentation_url": "https://docs.api.com/errors/CODE"
}
}
Standard Error Codes:
| HTTP Status | Code | Use Case |
|---|---|---|
| 400 | VALIDATION_ERROR | Invalid input |
| 400 | INVALID_FORMAT | Malformed JSON, wrong content type |
| 401 | UNAUTHORIZED | Missing or invalid auth |
| 401 | TOKEN_EXPIRED | Auth token expired |
| 403 | FORBIDDEN | Valid auth, insufficient permissions |
| 404 | NOT_FOUND | Resource doesn't exist |
| 409 | CONFLICT | Resource state conflict |
| 422 | UNPROCESSABLE | Valid format, invalid semantics |
| 429 | RATE_LIMITED | Too many requests |
| 500 | INTERNAL_ERROR | Server-side failure |
| 503 | SERVICE_UNAVAILABLE | Maintenance or overload |
API Versioning Strategies
| Strategy | Example | Pros | Cons |
|---|---|---|---|
| URL path | /v1/users | Clear, cacheable | URL pollution |
| Header | API-Version: 2024-01 | Clean URLs | Less visible |
| Query param | /users?version=1 | Easy testing | Cache issues |
| Content type | Accept: application/vnd.api.v1+json | RESTful | Complex |
Recommended: URL path versioning for major versions, header-based for minor changes.
Request/Response Examples
List Endpoint Pattern:
// GET /workspaces/{id}/members?limit=20&cursor=abc123
// Response
{
"data": [
{
"id": "user-1",
"email": "[email protected]",
"permission_level": "editor",
"joined_at": "2024-01-10T10:00:00Z"
},
{
"id": "user-2",
"email": "[email protected]",
"permission_level": "owner",
"joined_at": "2024-01-05T08:00:00Z"
}
],
"pagination": {
"cursor": "def456",
"has_more": true,
"total_count": 47
}
}
Single Resource Pattern:
// GET /workspaces/{id}
// Response
{
"data": {
"id": "workspace-123",
"name": "Q4 Planning",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"owner": {
"id": "user-1",
"email": "[email protected]"
},
"member_count": 12,
"settings": {
"visibility": "private",
"allow_guest_access": false
}
},
"_links": {
"self": "/workspaces/workspace-123",
"members": "/workspaces/workspace-123/members",
"invitations": "/workspaces/workspace-123/invitations"
}
}
Pagination Standards
| Style | Best For | Example |
|---|---|---|
| Cursor | Large datasets, real-time data | ?cursor=eyJpZCI6MTIzfQ |
| Offset | Stable datasets, jump-to-page | ?offset=40&limit=20 |
| Keyset | Ordered results, efficient DB | ?after_id=123&limit=20 |
Always include:
- Current page indicator
- Has more indicator
- Total count (if performant)
API Documentation Checklist
Endpoint Documentation
├── □ HTTP method and path
├── □ Summary (one line)
├── □ Description (detailed)
├── □ Authentication requirements
├── □ Path parameters (with types, constraints)
├── □ Query parameters (with defaults)
├── □ Request body schema
├── □ Response schemas (all status codes)
├── □ Real examples (copy-pasteable)
└── □ Error codes and meanings
API-Wide Documentation
├── □ Authentication guide
├── □ Rate limiting policy
├── □ Versioning policy
├── □ Pagination guide
├── □ Error handling guide
├── □ Changelog
└── □ SDK/client library links
Anti-Patterns
- Undocumented endpoints — "It's obvious from the code"
- Example-free specs — Schema without concrete examples
- Error amnesia — Only documenting 200 responses
- Version neglect — No versioning strategy until breaking change
- Inconsistent naming —
user_idin one endpoint,userIdin another - Kitchen sink responses — Returning everything instead of what's needed
- Chatty APIs — Multiple calls needed for one logical operation
- Undocumented limits — Rate limits, pagination, max sizes not specified
- Stale specs — Documentation doesn't match implementation
- Internal exposure — Leaking implementation details in error messages
title: Acceptance Criteria impact: CRITICAL tags: acceptance-criteria, testing, qa, definition-of-done, gherkin
Acceptance Criteria
Impact: CRITICAL
Acceptance criteria define the contract between PM, engineering, and QA. They answer: "How do we know this story is done?" Without clear criteria, you get endless debates, missed requirements, and rework.
Purpose of Acceptance Criteria
- Shared understanding — Everyone agrees what "done" means
- Testable conditions — QA can verify each criterion
- Scope boundaries — Prevents feature creep during development
- Estimation input — Engineers understand complexity upfront
Given-When-Then Format (Gherkin)
The gold standard for testable acceptance criteria:
Given [precondition/context]
When [action/trigger]
Then [expected outcome]
Multiple Conditions:
Given [precondition]
And [additional precondition]
When [action]
Then [outcome]
And [additional outcome]
But [exception/exclusion]
Acceptance Criteria Patterns
| Pattern | Use When | Example |
|---|---|---|
| Happy Path | Describing normal flow | User logs in successfully |
| Error State | Invalid input/failure | Wrong password shows error |
| Edge Case | Boundary conditions | Cart with 999 items |
| Permission | Access control | Admin-only action blocked for user |
| State Change | Before/after conditions | Draft → Published |
| Performance | Speed requirements | Page loads in <2 seconds |
Good Acceptance Criteria Examples
Feature: Password Reset
Scenario: Successful password reset request
Given I am on the login page
And I have a registered account with email "[email protected]"
When I click "Forgot Password"
And I enter my email address
And I click "Send Reset Link"
Then I see confirmation message "Check your email for reset instructions"
And I receive an email within 60 seconds
And the email contains a unique reset link valid for 24 hours
Scenario: Password reset with unregistered email
Given I am on the forgot password page
When I enter an email not in our system
And I click "Send Reset Link"
Then I see the same confirmation message (security: don't reveal if email exists)
And no email is sent
Scenario: Password reset link expiration
Given I requested a password reset more than 24 hours ago
When I click the reset link in my email
Then I see "This link has expired"
And I see option to request a new reset link
Scenario: New password validation
Given I clicked a valid reset link
When I enter a new password
Then the password must be at least 8 characters
And contain at least one uppercase letter
And contain at least one number
And show strength indicator (weak/medium/strong)
Scenario: Successful password change
Given I entered a valid new password
When I click "Reset Password"
Then my password is updated
And I am logged in automatically
And I receive confirmation email
And all other sessions are invalidated
Feature: Shopping Cart
Scenario: Add item to empty cart
Given my cart is empty
When I add a product priced at $25.00
Then my cart shows 1 item
And the subtotal shows $25.00
And the cart icon shows badge with "1"
Scenario: Add same item multiple times
Given I have 2 units of "Blue Widget" in my cart
When I add another "Blue Widget"
Then my cart shows 3 units of "Blue Widget"
And the quantity is consolidated (not separate line items)
Scenario: Add item exceeding inventory
Given a product has 5 units in stock
And I already have 5 in my cart
When I try to add another
Then I see "Maximum available quantity reached"
And my cart quantity remains at 5
Scenario: Cart persistence across sessions
Given I am logged in with items in my cart
When I log out and log back in
Then my cart items are preserved
And quantities match what I had before
Scenario: Price change after adding to cart
Given I added an item priced at $50.00
And the price later changes to $45.00
When I view my cart
Then I see the current price of $45.00
And I see "Price reduced from $50.00" notice
Bad Acceptance Criteria Examples
Too Vague:
- User can reset password
- It should be secure
- Good user experience
Why it fails: Not testable. What does "secure" mean? What's "good"?
Too Implementation-Specific:
- When POST /api/auth/reset is called with valid email,
return 200 and insert row into password_reset_tokens table
with SHA-256 hashed token
Why it fails: Dictates implementation details. Focus on behavior, not code.
Missing Edge Cases:
Given I enter my email
When I click reset
Then I get an email
Why it fails: What if email invalid? What if not registered? What if rate limited?
Incomplete:
- User can add items to cart
Why it fails: Add how many? What about inventory limits? Does it persist? What feedback do they see?
Acceptance Criteria Checklist
For each user story, ensure criteria cover:
Functional Requirements
├── □ Happy path (normal success flow)
├── □ Validation (input requirements)
├── □ Error states (what can go wrong)
├── □ Edge cases (boundaries, limits)
├── □ Permissions (who can/cannot)
└── □ State transitions (before/after)
Non-Functional Requirements
├── □ Performance (speed, limits)
├── □ Accessibility (screen reader, keyboard)
├── □ Security (auth, data protection)
└── □ Compatibility (browsers, devices)
User Experience
├── □ Feedback (success/error messages)
├── □ Loading states (spinners, skeletons)
└── □ Empty states (no data scenarios)
Acceptance Criteria Table Format
For simpler features, tables can be effective:
Login Validation:
| Input | Expected Result |
|---|---|
| Valid email + correct password | Login succeeds, redirect to dashboard |
| Valid email + wrong password | "Invalid credentials" error, remain on login |
| Invalid email format | "Please enter valid email" inline error |
| Empty email | "Email is required" inline error |
| Empty password | "Password is required" inline error |
| Account locked (5+ failed attempts) | "Account locked. Reset password or wait 30 min" |
| Unverified email account | "Please verify your email first" + resend option |
Definition of Done vs Acceptance Criteria
| Concept | Scope | Example |
|---|---|---|
| Acceptance Criteria | Per story | "Given X, when Y, then Z" |
| Definition of Done | All stories | Code reviewed, tests pass, docs updated |
Definition of Done (team-wide):
□ All acceptance criteria pass
□ Code reviewed and approved
□ Unit tests written (>80% coverage)
□ Integration tests pass
□ No critical/high security issues
□ Accessibility audit pass
□ Documentation updated
□ Deployed to staging
□ PM sign-off
Writing Criteria for Different Story Types
UI/Frontend Stories:
- Include visual states (loading, error, success, empty)
- Specify responsive behavior
- Note animation/transition expectations
- Reference design specs
API/Backend Stories:
- Include request/response formats
- Specify error codes and messages
- Define rate limits and quotas
- Note caching behavior
Integration Stories:
- Define handoff points
- Specify retry/fallback behavior
- Document timeout expectations
- Clarify data format conversions
Anti-Patterns
- Criteria as requirements — Writing new requirements in AC instead of the story
- Gold plating — Adding criteria not related to the story
- Assumption hiding — Criteria that assume shared knowledge ("handles the usual cases")
- Test case masquerading — Low-level test steps instead of behavior
- Changing mid-sprint — Adding criteria after development started
- Checkbox syndrome — Criteria so broad they're always "met" ("it works")
- Missing negatives — Only happy paths, no error scenarios
- Copy-paste templates — Same boilerplate criteria on every story
title: Design Handoff Documentation impact: MEDIUM-HIGH tags: design, handoff, ui, ux, components, specifications
Design Handoff Documentation
Impact: MEDIUM-HIGH
Design handoff docs bridge the gap between design files and working code. They translate visual designs into implementable specifications, preventing the "that's not what I meant" rework cycle.
Design Handoff Components
| Component | Purpose | Who Creates |
|---|---|---|
| Component Specs | Individual UI element details | Designer |
| Interaction Specs | Behaviors, transitions, animations | Designer |
| Responsive Specs | Breakpoints, layout changes | Designer |
| Content Specs | Copy, microcopy, character limits | Product/Design |
| Accessibility Specs | WCAG requirements, screen reader | Designer |
| Asset Handoff | Icons, images, fonts | Designer |
| Edge State Specs | Loading, empty, error states | Product/Design |
Component Specification Template
## Component: [Name]
### Visual Reference
[Screenshot or Figma link]
### Properties
| Property | Type | Default | Options |
|----------|------|---------|---------|
| variant | string | "primary" | primary, secondary, ghost |
| size | string | "medium" | small, medium, large |
| disabled | boolean | false | - |
| loading | boolean | false | - |
| icon | string | null | icon name or null |
| fullWidth | boolean | false | - |
### Anatomy
[Diagram showing component parts]
| Part | Token/Value | Notes |
|------|-------------|-------|
| Container | padding-x: 16px, padding-y: 8px | |
| Text | font-body-medium | Truncate with ellipsis |
| Icon | 20x20px | Left-aligned, 8px gap |
| Border | 1px solid gray-300 | Only for secondary |
### States
| State | Visual Change | Token |
|-------|---------------|-------|
| Default | - | bg-primary |
| Hover | Darken 10% | bg-primary-hover |
| Active | Darken 20% | bg-primary-active |
| Focus | 2px ring | ring-focus |
| Disabled | 50% opacity | opacity-50 |
| Loading | Spinner replaces text | - |
### Responsive Behavior
| Breakpoint | Behavior |
|------------|----------|
| Mobile (<640px) | Full width, stacked icons |
| Tablet (640-1024px) | Auto width, inline icons |
| Desktop (>1024px) | Fixed width options available |
### Accessibility
- Role: button
- Keyboard: Enter/Space to activate
- Focus: Visible focus ring
- Screen reader: Announce loading state
- Color contrast: Minimum 4.5:1
### Usage Guidelines
**Do:**
- Use primary for main actions
- One primary button per section
- Use loading state for async actions
**Don't:**
- Don't use multiple primary buttons together
- Don't disable without explaining why
- Don't use ghost for important actions
Good Design Handoff Example
# Design Handoff: Workspace Invitation Modal
## Overview
Modal for workspace owners to invite new team members. Appears when
clicking "Invite" button in workspace header.
**Figma:** [Link to designs]
**Prototype:** [Link to prototype]
## Modal Container
| Property | Value | Token |
|----------|-------|-------|
| Width | 480px | - |
| Max Height | 80vh | - |
| Padding | 24px | spacing-6 |
| Border Radius | 12px | radius-lg |
| Background | White | bg-surface |
| Shadow | Large | shadow-lg |
| Backdrop | 50% black | overlay-50 |
### Animation
| Action | Animation |
|--------|-----------|
| Open | Fade in (200ms) + scale from 95% |
| Close | Fade out (150ms) |
| Backdrop click | Close modal |
| Escape key | Close modal |
## Header Section
┌─────────────────────────────────────────┐ │ [Icon] Invite to Workspace [X] │ │ Add team members to "Q4 Planning" │ └─────────────────────────────────────────┘
| Element | Spec |
|---------|------|
| Title | text-lg, font-semibold, gray-900 |
| Subtitle | text-sm, gray-600 |
| Close button | 24x24, gray-500, hover: gray-700 |
| Icon | 20x20, primary color |
| Gap between title/subtitle | 4px |
## Form Section
### Email Input
| Property | Value |
|----------|-------|
| Label | "Email address" |
| Placeholder | "[email protected]" |
| Type | email |
| Validation | Real-time email format |
| Error | Inline, below input |
**States:**
| State | Border | Background | Text |
|-------|--------|------------|------|
| Default | gray-300 | white | gray-900 |
| Focus | primary-500 | white | gray-900 |
| Error | red-500 | red-50 | gray-900 |
| Disabled | gray-200 | gray-50 | gray-500 |
### Permission Dropdown
| Property | Value |
|----------|-------|
| Label | "Permission level" |
| Default | "Editor" |
| Options | Viewer, Editor, Owner |
| Width | Full width |
**Option Display:**
┌─────────────────────────────────┐ │ Editor ▼ │ ├─────────────────────────────────┤ │ Viewer │ │ Can view content │ ├─────────────────────────────────┤ │ Editor ✓ │ │ Can view and edit content │ ├─────────────────────────────────┤ │ Owner │ │ Full access including settings │ └─────────────────────────────────┘
### Optional Message (Collapsed by Default)
| Property | Value |
|----------|-------|
| Toggle | "Add a personal message" link |
| Textarea | 3 rows default, auto-expand |
| Character limit | 500 |
| Counter | "0/500" aligned right |
## Footer Section
┌─────────────────────────────────────────┐ │ [Cancel] [Send Invite]│ └─────────────────────────────────────────┘
| Button | Variant | Behavior |
|--------|---------|----------|
| Cancel | Ghost | Close modal, no action |
| Send Invite | Primary | Validate, submit, close |
**Button States:**
| State | Send Invite |
|-------|-------------|
| Default | Enabled |
| Invalid form | Disabled, tooltip: "Enter valid email" |
| Submitting | Loading spinner, text: "Sending..." |
| Success | Close modal, show toast |
## Edge States
### Empty State
N/A (modal always has form)
### Loading State
While checking if email is already member:
- Show spinner in email input
- Disable submit button
### Error States
| Error | Display |
|-------|---------|
| Invalid email | Inline error: "Please enter a valid email" |
| Already member | Inline error: "This person is already a member" |
| Invitation pending | Inline warning: "Invitation pending. Resend?" |
| Workspace full | Banner at top: "Member limit reached (50/50)" |
| Network error | Toast: "Couldn't send. Check connection." |
### Success State
- Modal closes
- Toast: "Invitation sent to [email protected]"
- Members list updates (if visible)
## Responsive Behavior
| Breakpoint | Changes |
|------------|---------|
| Desktop (>768px) | Centered modal, 480px width |
| Tablet (640-768px) | Centered modal, 90% width |
| Mobile (<640px) | Full screen drawer from bottom |
### Mobile Drawer Specifics
- Slides up from bottom
- Full width, rounded top corners
- Max height 90vh
- Handle bar at top for drag-to-close
## Accessibility Checklist
- [ ] Focus trapped inside modal when open
- [ ] First focusable element (email input) auto-focused
- [ ] Escape key closes modal
- [ ] aria-labelledby points to title
- [ ] aria-describedby points to subtitle
- [ ] Close button has aria-label="Close"
- [ ] Form inputs have associated labels
- [ ] Error messages linked with aria-describedby
- [ ] Submit button announces loading state
## Content Specifications
| Element | Copy | Character Limit |
|---------|------|-----------------|
| Modal title | "Invite to Workspace" | 30 |
| Subtitle | "Add team members to [Workspace Name]" | Dynamic |
| Email label | "Email address" | - |
| Email placeholder | "[email protected]" | - |
| Permission label | "Permission level" | - |
| Message toggle | "Add a personal message" | - |
| Cancel button | "Cancel" | - |
| Submit button | "Send Invite" | - |
| Submit loading | "Sending..." | - |
| Success toast | "Invitation sent to [email]" | Dynamic |
## Assets Required
| Asset | Format | Sizes |
|-------|--------|-------|
| Invite icon | SVG | 20x20 |
| Close icon | SVG | 24x24 |
| Dropdown arrow | SVG | 12x12 |
| Checkmark | SVG | 16x16 |
| Spinner | SVG/CSS | 16x16 |
## Implementation Notes
- Use existing Modal component from design system
- Email validation should match backend regex
- Debounce email check (500ms) to reduce API calls
- Pre-fill email if inviting from contact list
Bad Design Handoff Example
# Invitation Modal
See Figma for designs.
Buttons should work.
Make it look good on mobile.
Why it fails:
- No specifications, just pointers
- No states or interactions documented
- No responsive behavior details
- No accessibility requirements
- No content specifications
Design Token Reference
Include token mappings for consistency:
## Design Tokens Reference
### Spacing
| Token | Value | Use |
|-------|-------|-----|
| spacing-1 | 4px | Tight grouping |
| spacing-2 | 8px | Related elements |
| spacing-4 | 16px | Section padding |
| spacing-6 | 24px | Large gaps |
### Typography
| Token | Value | Use |
|-------|-------|-----|
| text-xs | 12px/16px | Captions |
| text-sm | 14px/20px | Secondary text |
| text-base | 16px/24px | Body |
| text-lg | 18px/28px | Subheadings |
| text-xl | 20px/28px | Headings |
### Colors
| Token | Value | Use |
|-------|-------|-----|
| gray-50 | #F9FAFB | Background |
| gray-500 | #6B7280 | Secondary text |
| gray-900 | #111827 | Primary text |
| primary-500 | #3B82F6 | Primary actions |
| red-500 | #EF4444 | Errors |
| green-500 | #22C55E | Success |
Handoff Checklist
Visual Specs
├── □ All states documented (default, hover, active, focus, disabled)
├── □ Spacing and dimensions specified
├── □ Typography tokens referenced
├── □ Color tokens referenced
├── □ Border radius and shadows noted
Interaction Specs
├── □ Animations/transitions defined
├── □ Keyboard interactions noted
├── □ Touch interactions noted
├── □ Loading states designed
├── □ Error states designed
├── □ Empty states designed
Responsive Specs
├── □ Breakpoints defined
├── □ Layout changes per breakpoint
├── □ Touch target sizes verified (min 44px)
Accessibility Specs
├── □ Color contrast verified (4.5:1 text, 3:1 UI)
├── □ Focus states visible
├── □ Screen reader content specified
├── □ Keyboard navigation flow defined
Content Specs
├── □ All copy provided
├── □ Character limits defined
├── □ Error messages written
├── □ Success messages written
Assets
├── □ Icons exported (SVG)
├── □ Images exported (proper formats/sizes)
├── □ Fonts documented
Anti-Patterns
- Figma-only handoff — "Everything is in Figma" (engineering shouldn't have to interpret)
- Missing states — Only designing happy path, no loading/error/empty
- Pixel-perfect tyranny — Specs so rigid they ignore platform conventions
- No responsive specs — Desktop designs with "make it work on mobile"
- Accessibility afterthought — No a11y specs until audit fails
- Undocumented animations — "It should feel smooth" without timing
- Missing content — Lorem ipsum in production
- No edge cases — What happens with 100 characters? 1000?
- Stale handoffs — Designs change, specs don't update
title: Edge Cases and Error Handling impact: HIGH tags: edge-cases, errors, error-handling, failure-modes, resilience
Edge Cases and Error Handling
Impact: HIGH
Edge cases and error handling separate polished products from frustrating ones. Documenting failure modes upfront prevents surprises in production and reduces debugging time.
Why Document Edge Cases
- Prevent production surprises — Known unknowns are better than unknown unknowns
- Enable QA coverage — Testers need to know what to test
- Guide error messages — Users need helpful feedback
- Inform monitoring — Know what to alert on
- Reduce tech debt — Handle cases properly the first time
Edge Case Categories
| Category | Description | Example |
|---|---|---|
| Boundary | Min/max limits | 0 items, max characters |
| Timing | Race conditions, expiration | Concurrent edits, expired session |
| State | Invalid transitions | Cancel paid order, edit deleted item |
| Data | Missing, corrupt, unexpected | Null values, unicode, large files |
| External | Third-party failures | API down, timeout, rate limited |
| Permission | Access edge cases | Deleted user, transferred ownership |
| Network | Connectivity issues | Offline, slow connection, timeout |
| Concurrency | Simultaneous operations | Double submit, parallel updates |
Edge Case Documentation Template
## Edge Case: [Name]
**Category:** [Boundary/Timing/State/Data/External/Permission/Network/Concurrency]
**Likelihood:** [Common/Occasional/Rare]
**Impact:** [Critical/High/Medium/Low]
**Scenario:**
[Describe the specific situation]
**Current Behavior:**
[What happens now, if anything]
**Desired Behavior:**
[What should happen]
**User Message:**
[Exact error message to display]
**Recovery Action:**
[What user can do to resolve]
**Technical Notes:**
[Implementation considerations]
Comprehensive Edge Case Example
Feature: File Upload
## Edge Cases: File Upload
### Boundary Cases
| Case | Limit | Behavior | User Message |
|------|-------|----------|--------------|
| File too large | >100MB | Reject before upload | "File exceeds 100MB limit. Try compressing or splitting." |
| File name too long | >255 chars | Truncate with hash | N/A (silent truncation) |
| Zero-byte file | 0 bytes | Allow (may be intentional) | N/A |
| Filename with special chars | Unicode, spaces | Sanitize on backend | N/A (accept as-is, sanitize storage name) |
### Timing Cases
| Case | Trigger | Behavior | User Message |
|------|---------|----------|--------------|
| Upload timeout | >5 min upload | Retry with resume | "Upload interrupted. Resuming..." |
| Session expires mid-upload | Auth token expires | Complete upload, fail on save | "Session expired. Please log in and retry." |
| User navigates away | Browser tab closed | Cancel upload | Confirmation: "Upload in progress. Leave anyway?" |
### State Cases
| Case | Trigger | Behavior | User Message |
|------|---------|----------|--------------|
| Folder deleted during upload | Target deleted | Create folder or reject | "Destination folder no longer exists. Select new location." |
| Storage quota exceeded | Plan limit | Reject upload | "Storage limit reached. Upgrade plan or delete files." |
| Duplicate filename | Same name exists | Prompt for resolution | "File already exists. Replace, rename, or cancel?" |
### Data Cases
| Case | Trigger | Behavior | User Message |
|------|---------|----------|--------------|
| Corrupt file | Invalid header | Attempt upload, warn on view | "File may be corrupt. Upload anyway?" |
| Unsupported format | Blocked extension | Reject | "File type .exe not allowed. Supported: pdf, doc, jpg..." |
| Malware detected | Virus scan positive | Reject, log security event | "File flagged as potentially harmful. Contact support." |
| Image with EXIF data | Privacy concern | Strip EXIF on upload | N/A (silent strip) |
### External Dependency Cases
| Case | Trigger | Behavior | User Message |
|------|---------|----------|--------------|
| S3 unavailable | AWS outage | Queue for retry | "Upload processing. You'll be notified when complete." |
| Virus scanner timeout | Scan service slow | Allow with async scan | "File uploaded. Security scan in progress." |
| CDN propagation delay | New file not available | Show from origin | N/A (transparent fallback) |
### Network Cases
| Case | Trigger | Behavior | User Message |
|------|---------|----------|--------------|
| Connection lost | Network drop | Pause, auto-retry | "Connection lost. Will resume when online." |
| Slow upload (<100kb/s) | Poor connection | Show warning, continue | "Slow connection detected. Upload may take longer." |
| Packet loss | Unstable network | Retry chunks | N/A (transparent retry) |
### Concurrency Cases
| Case | Trigger | Behavior | User Message |
|------|---------|----------|--------------|
| Double click upload | User impatience | Debounce, single upload | N/A (ignore duplicate click) |
| Same file from two tabs | Multiple sessions | Both succeed, detect duplicate | "This file was uploaded in another tab." |
| Replace file during download | Concurrent access | Version old file | N/A (serve consistent version) |
Error Taxonomy
Organize errors by recoverability:
| Type | User Can Fix? | Response Strategy |
|---|---|---|
| Validation | Yes | Inline errors, clear instructions |
| Authentication | Yes | Redirect to login |
| Authorization | Sometimes | Explain permission, link to request access |
| Not Found | Sometimes | Search suggestions, "did you mean" |
| Conflict | Yes | Show current state, resolution options |
| Rate Limit | Wait | Show when to retry |
| Server Error | No | Apologize, suggest retry, link to status page |
| Maintenance | No | Estimated return time |
Error Message Guidelines
Structure:
[What happened] + [Why it matters] + [What to do next]
Good Error Messages:
| Situation | Good Message |
|---|---|
| Invalid email | "Please enter a valid email address (e.g., [email protected])" |
| Payment failed | "Payment declined by your bank. Try another card or contact your bank." |
| Permission denied | "You need Editor access to modify this document. Request access from Sarah M." |
| Rate limited | "You've made too many requests. Please wait 5 minutes before trying again." |
| Server error | "Something went wrong on our end. We've been notified. Try again in a few minutes." |
Bad Error Messages:
| Bad | Why | Better |
|---|---|---|
| "Error" | No information | "Unable to save changes" |
| "Error 403" | Technical jargon | "You don't have permission" |
| "Invalid input" | Vague | "Username must be 3-20 characters" |
| "Request failed" | No next step | "Request failed. Check connection and retry." |
| "null reference exception" | Exposes internals | "Something went wrong. Try again." |
Error Handling Matrix
| Error Type | Log Level | Alert? | User Feedback | Auto Retry? |
|---|---|---|---|---|
| Validation | Debug | No | Inline error | No |
| Auth failure | Info | No | Modal/redirect | No |
| Not found | Warn | If pattern | Empty state | No |
| Rate limit | Warn | If excessive | Toast | Yes (delayed) |
| Timeout | Warn | If SLA breach | Toast | Yes (3x) |
| DB error | Error | Yes | Generic error | Yes (2x) |
| Critical | Fatal | Yes (PagerDuty) | Maintenance page | No |
Documenting Failure Modes
For each integration/dependency:
## Dependency: Stripe Payment API
### Failure Modes
| Failure | Detection | Impact | Mitigation |
|---------|-----------|--------|------------|
| API timeout (>10s) | HTTP timeout | Payment stuck | Retry 3x, then queue |
| Invalid API key | 401 response | All payments fail | Alert, manual fix |
| Card declined | Decline code | Single payment fails | Show user message |
| Rate limited | 429 response | Slowdown | Exponential backoff |
| Webhook missed | No event received | Data out of sync | Polling reconciliation |
| API deprecation | Warning header | Future breakage | Log, plan upgrade |
### Fallback Behavior
- Primary: Stripe API direct call
- Retry: 3 attempts with exponential backoff (1s, 2s, 4s)
- Queue: If all retries fail, queue for background processing
- Alert: If queue depth > 100 or age > 1 hour
- Manual: Admin can force-retry or refund
### Recovery Procedures
1. Check Stripe status page
2. Verify API key validity
3. Check rate limit headers
4. Review recent code changes
5. Escalate to Stripe support if needed
Edge Case Discovery Checklist
When specifying a feature, ask:
Inputs
├── □ What if input is empty/null?
├── □ What if input is at minimum value?
├── □ What if input is at maximum value?
├── □ What if input exceeds maximum?
├── □ What if input has unexpected characters?
├── □ What if input has malicious content?
└── □ What if input is in wrong format?
Timing
├── □ What if action is very slow?
├── □ What if action times out?
├── □ What if action is interrupted?
├── □ What if session expires during action?
└── □ What if two users act simultaneously?
State
├── □ What if resource doesn't exist?
├── □ What if resource was just deleted?
├── □ What if resource is locked/in use?
├── □ What if user loses permission during action?
└── □ What if related resources change?
External
├── □ What if third-party service is down?
├── □ What if third-party returns unexpected data?
├── □ What if network is unavailable?
└── □ What if response is slow?
Anti-Patterns
- Happy path only — Only documenting success scenarios
- Generic errors — "Something went wrong" for everything
- Silent failures — Errors swallowed without feedback
- Technical messages — Showing stack traces to users
- Unhandled states — Loading forever, no empty states
- Inconsistent handling — Same error, different treatment
- No recovery path — Errors without guidance on fixing
- Over-alerting — Every error pages on-call
- Under-logging — No audit trail when things go wrong
- Blame the user — "Invalid input" without explaining what's valid
title: Documentation Maintenance impact: MEDIUM tags: maintenance, versioning, deprecation, lifecycle, documentation
Documentation Maintenance
Impact: MEDIUM
Documentation that's not maintained becomes worse than no documentation — it actively misleads. Establish clear processes for keeping specs current, versioning changes, and deprecating outdated content.
Documentation Lifecycle
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Draft │───▶│ Review │───▶│ Active │───▶│ Stale │───▶│ Archived│
└─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘
│ │ │ │ │
Writing Feedback In Use Outdated Historical
in progress & approval reference needs update reference only
Document Status System
Every spec document should have a status:
| Status | Badge | Meaning | Action Required |
|---|---|---|---|
| Draft | [DRAFT] | Work in progress | Do not rely on |
| Review | [REVIEW] | Ready for feedback | Provide feedback by date |
| Active | None | Current, accurate | Use as reference |
| Needs Update | [NEEDS UPDATE] | Known to be outdated | Update before using |
| Deprecated | [DEPRECATED] | Being phased out | See replacement doc |
| Archived | [ARCHIVED] | Historical only | Do not use |
Documentation Header Template
---
title: [Document Title]
status: active
version: 1.2.0
last_updated: 2024-01-15
owner: @username
reviewers: @reviewer1, @reviewer2
related_docs:
- [PRD: Feature Name](link)
- [Technical Spec](link)
---
# Document Title
> **Status:** Active
> **Version:** 1.2.0
> **Last Updated:** January 15, 2024
> **Owner:** Product Team (@username)
## Changelog
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 1.2.0 | 2024-01-15 | @username | Added mobile specs |
| 1.1.0 | 2024-01-10 | @username | Updated error handling |
| 1.0.0 | 2024-01-05 | @username | Initial release |
Versioning Strategy
Semantic Versioning for Docs:
| Version | When to Bump | Example Change |
|---|---|---|
| Major (X.0.0) | Breaking changes, major restructure | Completely new approach |
| Minor (x.Y.0) | New sections, significant additions | Added API section |
| Patch (x.y.Z) | Corrections, clarifications | Fixed typo, updated date |
When to Create New Version vs. Update:
- Same document: Minor clarifications, corrections
- New version: Significant changes to approach or scope
- New document: Completely different feature or requirement
Review Schedule
| Document Type | Review Frequency | Trigger Events |
|---|---|---|
| PRD | Per milestone | Scope change, pivot |
| Technical Spec | Per release | Architecture change |
| API Spec | Per version | Breaking changes |
| User Stories | Per sprint | Refinement changes |
| Runbooks | Quarterly | Incident learnings |
| Style Guides | Semi-annually | Design system updates |
Documentation Review Checklist
## Quarterly Doc Review: [Document Name]
**Reviewer:** @username
**Review Date:** 2024-01-15
**Document Version:** 1.2.0
### Accuracy Check
- [ ] All links work (no 404s)
- [ ] Code examples still work
- [ ] Screenshots match current UI
- [ ] Referenced features still exist
- [ ] Metrics/numbers are current
### Completeness Check
- [ ] Covers current scope (nothing major missing)
- [ ] Edge cases still relevant
- [ ] Error handling still accurate
- [ ] Integration points current
### Relevance Check
- [ ] Still serving its purpose
- [ ] Audience still needs this
- [ ] Not superseded by another doc
### Action Items
- [ ] [List specific updates needed]
- [ ] [Assign owners and dates]
### Verdict
- [ ] **Active:** No changes needed
- [ ] **Needs Update:** Specific updates identified
- [ ] **Deprecate:** Superseded or no longer needed
Deprecation Process
When a document is being retired:
# [DEPRECATED] Original Document Title
> **DEPRECATED:** This document is no longer maintained.
> **Reason:** Replaced by [New Document Title](link)
> **Deprecated Date:** January 15, 2024
> **Removal Date:** April 15, 2024
---
## Why This Was Deprecated
[Brief explanation of why this document is being phased out]
## Migration Guide
| Old Concept | New Location | Notes |
|-------------|--------------|-------|
| Section A | [New Doc, Section X](link) | Mostly unchanged |
| Section B | Removed | No longer applicable |
| Section C | [Different Doc](link) | Significantly updated |
## Original Content Below
[Keep original content for reference during transition period]
Documentation Debt Indicators
Signs your docs are becoming tech debt:
| Indicator | Red Flag | Action |
|---|---|---|
| Age | No updates in 6+ months | Schedule review |
| Accuracy | Known inaccuracies not fixed | Prioritize fix |
| Completeness | Major sections marked "TBD" | Complete or remove |
| Relevance | Feature was deprecated | Archive doc |
| Ownership | No clear owner | Assign owner |
| Usage | No views in 3 months | Consider archiving |
| Feedback | Repeated questions about same topic | Improve clarity |
Documentation Maintenance Automation
Automated Checks:
| Check | Frequency | Alert |
|---|---|---|
| Broken links | Weekly | Slack notification |
| Stale docs (no updates in X days) | Monthly | Email to owner |
| Orphaned docs (no links to them) | Quarterly | Review queue |
| Missing owners | On change | Block merge |
| Expired review dates | Daily | Reminder notification |
Suggested Tooling:
- Link checkers: Built into most doc platforms
- Freshness tracking: Custom metadata + scripts
- Analytics: Doc platform analytics or custom
- Ownership: CODEOWNERS-style files for docs
Good Documentation Maintenance Example
# Documentation Maintenance Log: Workspace Sharing
## Active Documents
| Document | Version | Last Updated | Next Review | Owner |
|----------|---------|--------------|-------------|-------|
| PRD | 2.1.0 | 2024-01-15 | 2024-04-15 | @pm |
| Tech Spec | 1.3.0 | 2024-01-10 | 2024-02-10 | @eng |
| API Spec | 1.0.0 | 2024-01-05 | 2024-04-05 | @eng |
| Runbook | 1.1.0 | 2024-01-12 | 2024-04-12 | @sre |
## Recent Changes
### January 2024
**PRD v2.1.0 (Jan 15)**
- Added mobile sharing flow requirements
- Updated success metrics based on beta learnings
- Removed deprecated "public link" references
**Tech Spec v1.3.0 (Jan 10)**
- Updated architecture diagram with caching layer
- Added performance optimization section
- Fixed incorrect database schema
**Runbook v1.1.0 (Jan 12)**
- Added troubleshooting for invitation email delays
- Updated escalation contacts
## Upcoming Reviews
- [ ] Tech Spec review due Feb 10 (@eng)
- [ ] Quarterly PRD review due Apr 15 (@pm)
## Archived Documents
| Document | Archived Date | Reason | Replacement |
|----------|---------------|--------|-------------|
| Sharing RFC | 2024-01-01 | Converted to spec | Tech Spec v1.0 |
| Design Brief | 2024-01-05 | Incorporated into PRD | PRD Section 5 |
## Open Documentation Debt
| Item | Priority | Owner | Due |
|------|----------|-------|-----|
| Add mobile examples to API spec | Medium | @eng | Jan 31 |
| Update screenshots for new UI | Low | @design | Feb 15 |
Bad Documentation Maintenance Example
# Sharing Feature Docs
Last updated: sometime last year probably
See:
- sharing-spec.doc (on someone's machine)
- the wiki page (not sure which one)
- ask Jake, he knows
TODO: update this
Why it fails:
- No version control
- No clear locations
- No ownership
- No review process
- Uncertain accuracy
Documentation Cleanup Rituals
Monthly:
- Review "Needs Update" tagged docs
- Check for broken links
- Update stale screenshots
Quarterly:
- Full review of active docs
- Archive completed project docs
- Update documentation index
Per Release:
- Update version numbers
- Add changelog entries
- Review all referenced docs
Per Project Completion:
- Archive project-specific docs
- Extract learnings into permanent docs
- Update style guides if patterns emerged
Anti-Patterns
- Write once, read never — Docs created and forgotten
- Sacred documents — Fear of updating "official" docs
- Tribal knowledge — "Everyone knows" instead of documenting
- Documentation sprawl — Same info in multiple places
- Perfectionism paralysis — Not publishing until perfect
- Owner orphans — Docs without assigned maintainers
- Fake freshness — Updating date without actual review
- Archive aversion — Keeping outdated docs "just in case"
- Review theater — Marking reviewed without actually reading
- Wiki wilderness — No structure, search is only navigation
title: Success Metrics Definition impact: HIGH tags: metrics, kpis, measurement, analytics, success-criteria
Success Metrics Definition
Impact: HIGH
Success metrics answer the most important question: "Did we build the right thing?" Without clear metrics, you're shipping features into a void and can't learn or iterate effectively.
Why Define Metrics Upfront
- Alignment — Everyone agrees what success looks like
- Prioritization — Focus on what moves metrics
- Learning — Understand what works and what doesn't
- Accountability — Clear ownership of outcomes
- Resource allocation — Data-driven investment decisions
Metric Types
| Type | Purpose | Example | Timeframe |
|---|---|---|---|
| Primary | Core success measure | Conversion rate | Per feature |
| Secondary | Supporting indicators | Time to first action | Per feature |
| Guardrail | Ensure no regression | Page load time | Always |
| Input | Leading indicators | Signup attempts | Short-term |
| Output | Lagging results | Revenue | Long-term |
The Metrics Hierarchy
┌─────────────────────┐
│ North Star │
│ (Company success) │
└──────────┬──────────┘
│
┌──────────────────┼──────────────────┐
│ │ │
┌──────┴──────┐ ┌──────┴──────┐ ┌──────┴──────┐
│ Pillar 1 │ │ Pillar 2 │ │ Pillar 3 │
│ Acquisition │ │ Activation │ │ Retention │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
┌──────┴──────┐ ┌──────┴──────┐ ┌──────┴──────┐
│ Feature │ │ Feature │ │ Feature │
│ Metrics │ │ Metrics │ │ Metrics │
└─────────────┘ └─────────────┘ └─────────────┘
SMART Metrics Framework
Every metric should be:
| Criteria | Question | Bad Example | Good Example |
|---|---|---|---|
| Specific | What exactly are we measuring? | "Engagement" | "DAU/MAU ratio" |
| Measurable | Can we actually track it? | "User happiness" | "NPS score" |
| Achievable | Is the target realistic? | "100% retention" | "85% 30-day retention" |
| Relevant | Does it matter for this feature? | "Total users" (for niche feature) | "Feature adoption rate" |
| Time-bound | When do we measure? | "Eventually improve" | "Increase 10% by Q2" |
Metrics Definition Template
## Metric: [Name]
### Definition
| Property | Value |
|----------|-------|
| Name | Active Team Workspaces |
| Definition | Workspaces with ≥2 members and activity in last 7 days |
| Formula | COUNT(workspaces WHERE member_count >= 2 AND last_activity > now() - 7d) |
| Type | Primary |
| Owner | Product Team |
### Context
**Why this metric matters:**
Measures whether teams are getting value from the sharing feature.
Directly tied to team plan retention.
**How it connects to business goals:**
North Star: Weekly Active Teams
Pillar: Team Activation
This metric: Feature-level success
### Measurement
**Data Source:** Analytics warehouse (Snowflake)
**Calculation Frequency:** Daily
**Dashboard:** [Link to dashboard]
**Alert Threshold:** <90% of target for 3 consecutive days
### Targets
| Period | Baseline | Target | Stretch |
|--------|----------|--------|---------|
| Launch (Week 1) | 0 | 100 | 200 |
| Month 1 | 100 | 500 | 750 |
| Month 3 | 500 | 2,000 | 3,000 |
| Month 6 | 2,000 | 5,000 | 7,500 |
### Segments
Track this metric by:
- Plan type (Free, Teams, Enterprise)
- Company size (1-10, 11-50, 51-200, 200+)
- Acquisition cohort (month signed up)
- Geography (US, EU, APAC, Other)
### Caveats
- Excludes test/demo accounts
- "Activity" = any create/edit/view event
- Gaming risk: Low (activity definition is broad)
Good Metrics Specification Example
# Success Metrics: Workspace Sharing Feature
## Overview
| Metric Type | Metric | Target | Measurement |
|-------------|--------|--------|-------------|
| Primary | Team activation rate | 30% | % of Teams accounts using sharing |
| Secondary | Time to first invite | <24 hours | Median time from workspace creation |
| Guardrail | Workspace load time | <2s p95 | No regression from adding sharing |
| Input | Invitations sent | 1,000/week | Leading indicator of adoption |
## Primary Metric: Team Activation Rate
### Definition
Percentage of Teams plan accounts that have invited at least one
member to at least one workspace within 30 days of signing up.
### Formula
team_activation_rate = COUNT(teams_accounts WHERE invited_member = true AND account_age <= 30d) / COUNT(teams_accounts WHERE account_age <= 30d)
### Why This Metric
- Directly measures if teams are getting value
- Predictive of retention (correlated 0.7)
- Actionable (we can improve invitation flow)
- Not gameable (requires real action)
### Current State
- Baseline: N/A (new feature)
- Comparable: Email invitation rate = 15%
- Industry benchmark: Team features ~25-35%
### Targets
| Milestone | Target | Rationale |
|-----------|--------|-----------|
| Week 1 | 5% | Early adopters only |
| Month 1 | 15% | Ramp with awareness |
| Month 3 | 25% | Optimization based on learning |
| Month 6 | 35% | Mature adoption |
### Segmentation
- By plan tier (Teams vs Enterprise)
- By company size
- By acquisition channel
- By industry vertical
## Secondary Metric: Time to First Invite
### Definition
Median time from workspace creation to first invitation sent,
for workspaces that eventually have invitations.
### Formula
time_to_first_invite = MEDIAN( first_invitation_timestamp - workspace_created_timestamp WHERE workspace.invitation_count > 0 )
### Why This Metric
- Measures friction in invitation flow
- Faster = better user experience
- Can optimize specific steps
### Current State
- Baseline: N/A (new feature)
- Hypothesis: <24 hours is healthy
### Targets
| Milestone | Target | Rationale |
|-----------|--------|-----------|
| Launch | <48 hours | Initial discovery |
| Month 1 | <24 hours | Improved onboarding |
| Month 3 | <12 hours | Streamlined flow |
## Guardrail Metric: Workspace Load Time
### Definition
95th percentile page load time for workspace pages.
### Why This Metric
Ensure sharing feature doesn't regress core experience.
### Threshold
- Current baseline: 1.8s p95
- Maximum acceptable: 2.0s p95
- Alert if: >2.0s for 15 minutes
### Action if Breached
1. Roll back sharing feature
2. Investigate performance
3. Optimize before re-enabling
## Input Metric: Invitations Sent
### Definition
Total number of workspace invitations sent per week.
### Why This Metric
Leading indicator of adoption. If invitations drop, investigate
before it affects activation rate.
### Targets
| Week | Target | Notes |
|------|--------|-------|
| 1 | 100 | Internal + alpha |
| 2 | 300 | Beta expansion |
| 3 | 700 | Wider beta |
| 4 | 1,500 | GA |
| Steady state | 2,000+/week | Ongoing |
## Metric Dependencies
Invitations Sent (Input) │ ▼ Invitations Accepted (Conversion) │ ▼ Active Team Workspaces (Engagement) │ ▼ Team Activation Rate (Primary) │ ▼ Team Plan Retention (Business Outcome)
## Dashboard Requirements
### Real-time View
- Invitations sent (last 24 hours)
- Error rates
- Load times
### Daily View
- Activation rate trend
- Time to first invite distribution
- Funnel conversion rates
### Weekly View
- Segment breakdown
- Cohort analysis
- Feature usage patterns
## Analytics Events
| Event | Trigger | Properties |
|-------|---------|------------|
| `invitation_sent` | Invite submitted | workspace_id, permission_level |
| `invitation_accepted` | Invite clicked and accepted | workspace_id, days_pending |
| `invitation_expired` | 7-day expiration | workspace_id |
| `member_added` | User joins workspace | workspace_id, source |
| `member_removed` | User removed/leaves | workspace_id, reason |
Bad Metrics Specification Example
# Metrics: Sharing Feature
We will track:
- Number of users
- Engagement
- Customer satisfaction
Success = people use it.
Why it fails:
- No specific definitions
- No targets or baselines
- "Engagement" and "satisfaction" undefined
- No timeframes
- No measurement plan
Common Metrics by Feature Type
| Feature Type | Primary Metric | Secondary Metrics |
|---|---|---|
| Onboarding | Activation rate | Time to first value, drop-off points |
| Engagement | DAU/MAU ratio | Session length, feature usage |
| Conversion | Conversion rate | Funnel step rates, time to convert |
| Retention | D7/D30 retention | Churn rate, resurrection rate |
| Revenue | ARPU, LTV | Upgrade rate, expansion revenue |
| Performance | Page load time | Error rate, availability |
| Support | Ticket volume | Resolution time, CSAT |
Metrics Pitfalls to Avoid
| Pitfall | Problem | Solution |
|---|---|---|
| Vanity metrics | Big numbers that don't matter | Focus on actionable metrics |
| Gaming | Metric improves without real progress | Use multiple metrics, monitor behavior |
| Short-termism | Optimize metric, hurt long-term | Add guardrail metrics |
| Over-measurement | Track everything, act on nothing | Limit to 3-5 key metrics |
| Stale targets | Targets don't evolve with learning | Review quarterly |
Metrics Review Cadence
| Frequency | Review | Participants |
|---|---|---|
| Daily | Real-time dashboards | Engineering |
| Weekly | Metric trends, anomalies | Product + Engineering |
| Monthly | Progress to targets | Leadership |
| Quarterly | Target recalibration | Exec team |
Anti-Patterns
- Metric theater — Tracking metrics without acting on them
- Goal post moving — Changing targets when you miss them
- Survivor bias — Only measuring users who stuck around
- Correlation confusion — Assuming causation from correlation
- Local optimization — Improving metric while hurting overall experience
- Metric debt — Accumulating measurements nobody uses
- Undefined baseline — Targets without knowing where you're starting
- Success by omission — Not measuring what might show failure
- Proxy obsession — Optimizing proxy instead of real outcome
- Launch and forget — Setting metrics at launch, never reviewing
title: PRD Writing impact: CRITICAL tags: prd, requirements, product, vision, scope
PRD Writing
Impact: CRITICAL
A PRD is the single source of truth for what you're building and why. It aligns stakeholders, prevents scope creep, and gives engineering the context they need to make good decisions.
The PRD Purpose
A PRD answers these questions:
- Why are we building this? (Problem, opportunity)
- What are we building? (Solution, scope)
- For whom are we building? (Users, personas)
- How will we know it works? (Metrics, success criteria)
- What are the constraints? (Timeline, resources, dependencies)
PRD Structure Framework
| Section | Purpose | Length |
|---|---|---|
| Executive Summary | Quick overview for skimmers | 2-3 sentences |
| Problem Statement | Why this matters | 1-2 paragraphs |
| Goals & Success Metrics | How we measure success | Bulleted list |
| User Personas | Who we're building for | 1-2 personas |
| User Stories | What users can do | 5-15 stories |
| Scope | What's in and out | Two lists |
| Requirements | Detailed needs | Categorized list |
| Constraints | Limitations and dependencies | Bulleted list |
| Timeline | Key milestones | Table or list |
| Open Questions | Unresolved decisions | Bulleted list |
| Appendix | Supporting research, mocks | As needed |
Problem Statement Formula
Template:
[User segment] struggles with [problem] when trying to [goal].
Currently, they [workaround], which results in [pain/cost].
By building [solution], we can [benefit], which will [business impact].
Good PRD Example
# PRD: Team Workspace Sharing
## Executive Summary
Enable teams to share workspaces with granular permissions, reducing the
current friction of workspace duplication and manual access management.
## Problem Statement
Teams of 5+ members struggle with workspace collaboration. Currently,
users duplicate workspaces or share account credentials, leading to:
- 40% of support tickets related to access issues
- Average 3.2 duplicate workspaces per team
- Security risk from shared credentials
Customer interviews (n=23) identified this as the #1 requested feature.
## Goals & Success Metrics
**Primary Goal:** Reduce workspace duplication by 60% within 90 days of launch
| Metric | Current | Target | Measurement |
|--------|---------|--------|-------------|
| Duplicate workspaces per team | 3.2 | 1.3 | Analytics |
| Access-related support tickets | 40% | 15% | Zendesk |
| Team collaboration NPS | 32 | 50 | Survey |
**Secondary Goals:**
- Increase team plan upgrades by 25%
- Reduce time-to-collaborate for new team members by 50%
## User Personas
**Primary: Team Lead (Sarah)**
- Manages 5-10 team members
- Needs to control who sees what
- Pain: Spends 2+ hours/week managing access manually
**Secondary: Team Member (Alex)**
- Joins existing teams
- Needs quick access to relevant workspaces
- Pain: Waits 1-2 days for access requests
## User Stories
[See stories-* rules for detailed format]
1. As a team lead, I want to invite members to my workspace so that
they can collaborate without creating duplicates
2. As a team lead, I want to set permission levels so that I can
control who can edit vs. view
3. As a team member, I want to see all workspaces shared with me
so that I can quickly find what I need
## Scope
**In Scope (v1):**
- Workspace invitation by email
- Three permission levels: Owner, Editor, Viewer
- Invitation management (revoke, modify)
- Shared workspace indicator in UI
**Out of Scope (v1):**
- Public/link sharing
- Workspace transfer (change owner)
- Permission inheritance (folders)
- Guest access (external users)
## Requirements
### Functional Requirements
- FR-1: Users can invite up to 50 members per workspace
- FR-2: Invitations expire after 7 days if not accepted
- FR-3: Owners can modify permissions at any time
- FR-4: Members receive email notification on invitation
### Non-Functional Requirements
- NFR-1: Invitation flow completes in <2 seconds
- NFR-2: Permission changes apply within 30 seconds
- NFR-3: Support 1000 concurrent workspace members
## Constraints
**Technical:**
- Must integrate with existing auth system (Auth0)
- Cannot modify current workspace data model significantly
**Business:**
- Must ship before Q3 for enterprise sales push
- Design resources limited to 2 weeks
**Dependencies:**
- Email service capacity increase (Ops team)
- Auth0 plan upgrade for group claims
## Timeline
| Milestone | Date | Deliverable |
|-----------|------|-------------|
| Design complete | June 15 | Figma specs approved |
| API complete | July 1 | Backend ready for integration |
| Beta launch | July 15 | 10% rollout to Teams plan |
| GA launch | August 1 | 100% rollout |
## Open Questions
- [ ] Should free plans have sharing? (Decision: Product leadership)
- [ ] Max members per workspace? (Proposed: 50, pending Eng review)
- [ ] Email template ownership? (Marketing or Product?)
## Appendix
- [Customer interview summary](link)
- [Competitive analysis](link)
- [Design explorations](link)
Bad PRD Example
# PRD: Sharing Feature
## Overview
We need to add sharing to workspaces because customers want it.
## Requirements
- Add sharing
- Make it fast
- Should be secure
- Users should like it
## Timeline
ASAP - this is high priority
## Notes
Talk to engineering about what's possible.
Why this fails:
- No problem statement or business justification
- No success metrics or acceptance criteria
- Vague requirements ("fast", "secure", "like it")
- No scope boundaries — everything is implied
- No user context or personas
- Timeline without milestones
PRD Review Checklist
Before sharing a PRD, verify:
□ Problem is validated with data or research
□ Success metrics are specific and measurable
□ Scope clearly states what's OUT as well as IN
□ All user personas are represented in stories
□ Technical constraints are documented
□ Dependencies are identified with owners
□ Timeline has specific milestones
□ Open questions are explicitly listed
□ Stakeholders are identified for sign-off
PRD Versioning
| Version | Trigger | Documentation |
|---|---|---|
| Draft | Initial creation | Mark as "[DRAFT]" in title |
| Review | Ready for feedback | Share with stakeholders |
| Approved | Stakeholder sign-off | Record approvers and date |
| Updated | Scope change | Changelog section, version bump |
| Deprecated | Feature shipped/cancelled | Mark as "[ARCHIVED]" |
Anti-Patterns
- The Novel — 30-page PRDs nobody reads. Keep it scannable.
- The Wishlist — Everything the customer ever mentioned. Prioritize ruthlessly.
- The Solution Spec — Jumping to "how" before establishing "what" and "why"
- The Orphan — PRD without clear owner or stakeholders
- The Frozen Doc — PRD that never updates as learnings emerge
- The Assumption Factory — Missing validation, just "we think" statements
- The Feature Factory — Requirements without business outcomes
- Spec by Jira — Tickets without the connecting narrative
title: Feature Flags and Rollout Plans impact: MEDIUM-HIGH tags: feature-flags, rollout, deployment, experiments, releases
Feature Flags and Rollout Plans
Impact: MEDIUM-HIGH
Feature flags and rollout plans turn risky big-bang releases into controlled, reversible deployments. They enable experimentation, gradual rollouts, and instant rollbacks.
Why Feature Flags
- Risk reduction — Limit blast radius of bugs
- Faster iteration — Ship code without exposing features
- Experimentation — A/B test with real users
- Operational control — Disable features without deploys
- Customer control — Enable for specific accounts
Feature Flag Types
| Type | Purpose | Lifespan | Example |
|---|---|---|---|
| Release | Gate unreleased features | Short (weeks) | sharing_v2_enabled |
| Experiment | A/B testing | Short (days-weeks) | checkout_flow_experiment |
| Ops | Circuit breakers, load shedding | Permanent | heavy_report_enabled |
| Permission | Plan/role-based access | Permanent | enterprise_analytics |
| Kill Switch | Emergency disable | Permanent | third_party_integration |
Feature Flag Naming Convention
{scope}_{feature}_{purpose}
Examples:
- release_workspace_sharing_enabled
- experiment_pricing_page_variant
- ops_batch_processing_enabled
- permission_custom_domains_access
- kill_switch_stripe_integration
Feature Flag Specification Template
## Feature Flag: [Name]
### Overview
| Property | Value |
|----------|-------|
| Flag Name | `release_workspace_sharing_enabled` |
| Type | Release |
| Owner | Product Team |
| Created | 2024-01-15 |
| Expected Removal | 2024-03-01 |
### Description
Gates access to the new workspace sharing feature, including:
- Invite modal in workspace header
- Members tab in workspace settings
- Sharing-related API endpoints
### Targeting Rules
| Stage | Audience | Percentage | Start Date |
|-------|----------|------------|------------|
| Internal | @company.com emails | 100% | Jan 15 |
| Alpha | Specific accounts (list below) | 100% | Jan 22 |
| Beta | Teams plan users | 10% → 50% | Feb 1 |
| GA | All users | 100% | Feb 15 |
**Alpha Account List:**
- Acme Corp (acct_123)
- Beta Inc (acct_456)
- Gamma LLC (acct_789)
### Fallback Behavior
When flag is OFF:
- "Invite" button hidden in workspace header
- Sharing API endpoints return 404
- Direct links to sharing pages redirect to workspace
### Dependencies
| Dependency | Status |
|------------|--------|
| Sharing Service deployed | Required |
| Email templates ready | Required |
| Analytics events tracked | Required |
### Rollback Criteria
Immediately disable if:
- Error rate >1% on sharing endpoints
- >50 support tickets related to sharing
- Data integrity issues detected
### Metrics to Monitor
- `sharing.invitations.sent` — Expected increase
- `sharing.invitations.errors` — Should stay <0.1%
- `workspace.load_time` — Should not increase >100ms
- Support ticket volume — Monitor for sharing issues
### Cleanup Plan
After 100% rollout for 2 weeks:
1. Remove flag checks from code
2. Remove flag from configuration
3. Update documentation
4. Archive this spec
Rollout Plan Template
# Rollout Plan: [Feature Name]
## Overview
| Property | Value |
|----------|-------|
| Feature | Workspace Sharing |
| PRD Link | [Link] |
| Tech Spec Link | [Link] |
| Feature Flag | `release_workspace_sharing_enabled` |
| Target GA Date | February 15, 2024 |
## Pre-Launch Checklist
### Engineering Readiness
- [ ] Code merged to main
- [ ] Feature flag created and tested
- [ ] Database migrations complete
- [ ] Performance testing passed
- [ ] Security review approved
- [ ] Monitoring/alerting configured
### Product Readiness
- [ ] User documentation published
- [ ] Help center articles updated
- [ ] In-app tooltips configured
- [ ] Email templates approved
### Support Readiness
- [ ] Support team briefed
- [ ] FAQ document created
- [ ] Escalation path defined
- [ ] Known issues documented
### Marketing Readiness
- [ ] Announcement blog post drafted
- [ ] Social media posts scheduled
- [ ] Email campaign prepared (if applicable)
## Rollout Stages
### Stage 1: Internal Testing (Jan 15-21)
**Audience:** Internal employees only
**Goal:** Validate core functionality, find obvious bugs
| Task | Owner | Status |
|------|-------|--------|
| Enable for @company.com | Eng | |
| Conduct internal testing | QA | |
| Fix critical bugs | Eng | |
| Document known issues | PM | |
**Go/No-Go Criteria:**
- [ ] No critical bugs
- [ ] Core flows work end-to-end
- [ ] Internal team sign-off
### Stage 2: Alpha (Jan 22-31)
**Audience:** 10 design partner accounts
**Goal:** Validate with real users, gather feedback
| Task | Owner | Status |
|------|-------|--------|
| Enable for alpha accounts | Eng | |
| Schedule feedback calls | PM | |
| Monitor error rates | Eng | |
| Iterate on feedback | Team | |
**Alpha Accounts:**
1. Acme Corp — Sarah (PM), [email protected]
2. Beta Inc — John (CTO), [email protected]
3. [...]
**Go/No-Go Criteria:**
- [ ] NPS >30 from alpha users
- [ ] Error rate <0.5%
- [ ] No data integrity issues
- [ ] Alpha user sign-off
### Stage 3: Beta (Feb 1-14)
**Audience:** Teams plan users, gradual percentage rollout
**Goal:** Validate at scale, stress test
| Day | Percentage | Users | Notes |
|-----|------------|-------|-------|
| Feb 1 | 5% | ~500 | Initial beta |
| Feb 5 | 10% | ~1,000 | If no issues |
| Feb 8 | 25% | ~2,500 | Expand |
| Feb 12 | 50% | ~5,000 | Final beta |
**Monitoring:**
- Hourly check: Error rates, latency
- Daily check: Support tickets, user feedback
- Weekly: Analytics review
**Pause/Rollback Triggers:**
- Error rate >1% for 30 minutes
- Latency p99 >500ms for 30 minutes
- >10 support tickets/hour related to feature
- Any data corruption detected
### Stage 4: General Availability (Feb 15)
**Audience:** All users
**Goal:** Feature fully launched
| Task | Owner | Status |
|------|-------|--------|
| Ramp to 100% | Eng | |
| Publish announcement | Marketing | |
| Monitor closely (48 hours) | Eng | |
| Begin flag cleanup | Eng | |
## Rollback Plan
### Rollback Procedure
1. **Decision Maker:** On-call eng or PM
2. **Action:** Disable flag in LaunchDarkly
3. **Impact:** Feature immediately hidden for all users
4. **Data:** No data loss; existing memberships preserved
5. **Communication:** Status page update within 15 minutes
### Rollback Communication Templates
**Status Page (Incident):**
We are temporarily disabling workspace sharing while we investigate an issue. Existing workspace configurations are preserved. We expect to re-enable the feature within [timeframe].
**Customer Email (if needed):**
Subject: Temporary pause on Workspace Sharing
We've temporarily paused the new workspace sharing feature while we address an issue we discovered. Your existing workspace setup is safe and will work normally when we re-enable the feature.
We expect to have this resolved within [timeframe].
## Post-Launch
### Success Criteria (2 weeks post-GA)
- [ ] 20% of Teams accounts have used sharing
- [ ] Workspace duplication down 30%
- [ ] Access-related tickets down 25%
- [ ] No P0/P1 bugs outstanding
### Cleanup Tasks
- [ ] Remove feature flag from code (by Mar 1)
- [ ] Archive rollout documentation
- [ ] Retrospective meeting scheduled
- [ ] Share learnings with team
Rollout Strategies
| Strategy | Use Case | Risk Level |
|---|---|---|
| Big Bang | Simple changes, low risk | High |
| Percentage | Gradual exposure | Medium |
| Ring | Employee → Beta → GA | Low |
| Geography | Test in single region first | Low |
| Account | Specific customers | Very Low |
| Time-based | Enable during low traffic | Low |
Good Rollout Example
## Rollout: New Checkout Flow
### Strategy: Ring-based with percentage
Ring 1 (Week 1): Internal employees
├── 100% of @company.com
├── Validate all payment paths
└── Success: No checkout failures
Ring 2 (Week 2): Friendly customers
├── 50 accounts who opted in
├── Collect qualitative feedback
└── Success: NPS >40, no critical bugs
Ring 3 (Week 3): Canary
├── 1% of production traffic
├── Compare conversion rate to control
├── Success: Conversion within 5% of baseline
Ring 4 (Week 4): Gradual rollout
├── 1% → 5% → 10% → 25% → 50% → 100%
├── 24 hours between each stage
└── Success: Conversion improved or neutral
Rollback: Instant flag disable, fallback to old checkout
Bad Rollout Example
## Rollout: New Checkout Flow
Ship it on Monday. If there are problems, we'll fix them.
Why it fails:
- No staged rollout
- No success criteria
- No monitoring plan
- No rollback plan
- No communication plan
Feature Flag Hygiene
| Lifecycle Stage | Action |
|---|---|
| Creation | Document purpose, owner, expected removal date |
| Active | Review monthly, update targeting rules |
| Stale | After 90 days at 100%, schedule cleanup |
| Removal | Delete flag, remove code checks, archive docs |
Technical Debt Warning Signs:
- Flags older than 6 months
- Flags with no recent evaluations
- Flags with no documented owner
- Code checking multiple flags for same feature
Anti-Patterns
- Flag forever — Never removing flags, code becomes unmaintainable
- Flag explosion — Too many flags, impossible to understand state
- No rollback testing — Rollback plan not actually tested
- Big bang despite flags — Having flags but going 0→100%
- Flag as security — Using flags instead of proper auth
- Coupling flags — Flag A requires Flag B, creating dependencies
- Silent rollout — No monitoring during gradual rollout
- Premature celebration — Declaring success before cleanup
- No owner — Flags without clear ownership decay
- Flag naming chaos — Inconsistent names impossible to search
title: User Story Creation impact: CRITICAL tags: user-stories, agile, requirements, personas, jtbd
User Story Creation
Impact: CRITICAL
User stories translate business requirements into engineering work. They're not just ticket templates — they're communication tools that capture who benefits, what they need, and why it matters.
The Story Structure
Classic Format:
As a [persona/user type]
I want [capability/action]
So that [benefit/value]
Enhanced Format:
As a [persona] with [context/situation]
I want to [action/capability]
So that I can [immediate benefit]
Which enables [business outcome]
The INVEST Criteria
Every user story should be:
| Criteria | Question | Red Flag |
|---|---|---|
| Independent | Can it ship alone? | "Blocked by Story #47" |
| Negotiable | Can scope flex? | Over-specified implementation |
| Valuable | Does user benefit? | Technical task disguised as story |
| Estimable | Can we size it? | Too vague or too large |
| Small | Fits in a sprint? | Multi-week estimate |
| Testable | Can we verify done? | No acceptance criteria |
Story Sizing Guide
| Size | Days | Characteristics |
|---|---|---|
| XS | 0.5 | Config change, copy update |
| S | 1-2 | Single component, clear path |
| M | 3-5 | Multiple components, some unknowns |
| L | 5-8 | Cross-system, needs breakdown |
| XL | 8+ | Epic-level, must be split |
Rule of thumb: If you can't complete it in one sprint, it's not a story — it's an epic.
Good User Story Examples
E-commerce: Add to Cart
**Story:** Add product to shopping cart
**As a** shopper browsing products
**I want to** add items to my cart without leaving the product page
**So that** I can continue browsing without losing my selections
**Acceptance Criteria:**
- Given I'm on a product page with available inventory
When I click "Add to Cart"
Then the item is added and cart count updates within 500ms
- Given I'm on a product page with size variants
When I click "Add to Cart" without selecting a size
Then I see an inline error prompting size selection
- Given I already have 10 of this item in cart
When I try to add another
Then I see a message about quantity limits
**Edge Cases:**
- Product goes out of stock between page load and add
- User is not logged in
- Network failure during add
**Out of Scope:**
- Wishlist functionality
- Product recommendations
- Guest checkout flow
SaaS: Team Invitation
**Story:** Invite team member to workspace
**As a** workspace owner
**I want to** invite colleagues by email
**So that** they can collaborate on projects without creating duplicates
**Acceptance Criteria:**
- Given I have owner permissions
When I enter a valid email and click "Invite"
Then an invitation email is sent within 60 seconds
- Given the email is already a workspace member
When I try to invite them
Then I see "This person is already a member" message
- Given I've sent an invitation
When I view pending invitations
Then I see the email, sent date, and option to resend/revoke
**Technical Notes:**
- Use existing email service (SendGrid)
- Invitations expire after 7 days
- Max 50 members per workspace
**Dependencies:**
- Email template (Design: due June 10)
Bad User Story Examples
Too Vague:
As a user
I want better search
So that I can find things
Why it fails: Who is the user? What does "better" mean? What things? No acceptance criteria.
Too Technical:
As a developer
I want to refactor the auth module to use JWT tokens
So that the code is cleaner
Why it fails: This is a technical task, not a user story. No user value. Reframe as: "As a user, I want to stay logged in across devices..."
Too Large:
As an admin
I want to manage all users, roles, permissions, and audit logs
So that I can control access to the system
Why it fails: This is an epic. Split into: manage users, manage roles, manage permissions, view audit logs.
Missing Context:
As a user
I want to export data
So that I can use it elsewhere
Why it fails: Export what data? In what format? What's "elsewhere"? Add: "As a marketing manager, I want to export campaign analytics as CSV so that I can create reports in Excel."
Persona-Based Story Writing
Define personas before writing stories:
| Persona | Description | Goals | Frustrations |
|---|---|---|---|
| Admin Amy | IT administrator, 5+ years | Maintain security, reduce tickets | Manual processes, unclear audit |
| Power User Paul | Heavy daily user | Speed, keyboard shortcuts | Friction in common tasks |
| Newbie Nina | Just joined, learning | Quick onboarding | Confusing UI, hidden features |
| Executive Eve | Occasional user, decision-maker | Quick insights, dashboards | Too much detail, slow reports |
Then write stories from their perspective:
- "As Admin Amy, I want to bulk deactivate users so that offboarding is efficient"
- "As Power User Paul, I want keyboard shortcuts for common actions so that I can work faster"
Jobs-to-Be-Done Integration
Combine JTBD with user stories:
JTBD Format:
When [situation/trigger]
I want to [motivation/job]
So I can [expected outcome]
Example:
When I'm preparing for a client meeting in 10 minutes
I want to quickly pull last quarter's metrics
So I can answer questions confidently without fumbling through dashboards
This becomes the story:
As a sales rep preparing for client meetings
I want to see a one-page summary of key account metrics
So that I can quickly reference performance data during calls
Story Mapping
Organize stories into a map:
┌─────────────────────────────────────────────────┐
User │ Discovery │ Selection │ Purchase │ Use │
Journey └─────────────────────────────────────────────────┘
│ │ │ │
┌─────┴─────┐ ┌─────┴─────┐ ┌────┴────┐ ┌────┴────┐
Release 1 │ Search │ │ Compare │ │ Checkout│ │Dashboard│
(MVP) │ Browse │ │ Details │ │ Payment │ │ Basic │
└───────────┘ └───────────┘ └─────────┘ └─────────┘
│ │ │ │
┌─────┴─────┐ ┌─────┴─────┐ ┌────┴────┐ ┌────┴────┐
Release 2 │ Filters │ │ Reviews │ │ Save CC │ │ Reports │
│ Sort │ │ Compare │ │ Express │ │ Export │
└───────────┘ └───────────┘ └─────────┘ └─────────┘
Story Splitting Techniques
When a story is too large, split by:
| Technique | Example |
|---|---|
| Workflow steps | Register → Verify email → Set password |
| Business rules | Basic validation → Complex validation |
| Data variations | Single item → Bulk items |
| Operations | Create → Read → Update → Delete |
| User types | Admin → User → Guest |
| Platforms | Web → Mobile → API |
| Performance | Works → Works fast |
Anti-Patterns
- Story as task — "Implement login API" (where's the user value?)
- Compound stories — "As a user, I want X and Y and Z" (split them)
- Gold plating — Over-specified acceptance criteria that constrain solutions
- Missing "so that" — Stories without stated value are features without purpose
- Copy-paste personas — "As a user" everywhere instead of specific personas
- Story as spec — 500-word stories that leave no room for negotiation
- Orphan stories — Stories not connected to epics or goals
- Zombie stories — Old stories that linger in backlog, never prioritized or removed
title: Technical Specifications impact: HIGH tags: technical-spec, architecture, system-design, engineering
Technical Specifications
Impact: HIGH
Technical specs translate product requirements into engineering blueprints. They document architectural decisions, system interactions, and implementation approaches before code is written.
When to Write Technical Specs
| Complexity | Spec Needed? | Approach |
|---|---|---|
| Small (<1 day) | No | Inline comments, PR description |
| Medium (1-5 days) | Lightweight | Brief design doc section |
| Large (1-2 weeks) | Yes | Full technical spec |
| Critical (any size) | Yes | Full spec + review |
Always write a spec when:
- Multiple teams/systems involved
- Breaking changes to existing APIs
- New infrastructure or services
- Security-sensitive features
- Performance-critical paths
Technical Spec Structure
# Technical Spec: [Feature Name]
## Overview
[2-3 sentence summary of what and why]
## Goals
[What this design achieves]
## Non-Goals
[What this design explicitly does NOT address]
## Background
[Context needed to understand the problem]
## Detailed Design
[The meat of the spec: architecture, components, flows]
## Data Model
[Schema changes, new models, relationships]
## API Design
[Endpoints, contracts, error handling]
## Security Considerations
[Auth, encryption, vulnerabilities, compliance]
## Observability
[Logging, metrics, alerting]
## Rollout Plan
[Deployment strategy, feature flags, migrations]
## Alternatives Considered
[Other approaches and why they were rejected]
## Open Questions
[Unresolved decisions]
## References
[Related docs, RFCs, PRDs]
Good Technical Spec Example
# Technical Spec: Workspace Sharing Service
## Overview
Build a sharing service that enables workspace owners to invite team members
with granular permissions. This supports the "Team Collaboration" initiative
targeting 25% increase in team plan conversions.
## Goals
- Enable workspace sharing with Owner/Editor/Viewer permissions
- Support up to 50 members per workspace
- Sub-second permission checks on workspace access
- Zero-downtime migration for existing workspaces
## Non-Goals
- Public link sharing (planned for v2)
- Cross-organization sharing
- Real-time collaboration features (separate initiative)
## Background
Currently, users share workspaces by sharing credentials (security risk) or
duplicating workspaces (data sync issues). Support tickets related to access
management are 40% of total volume.
See: [PRD: Team Workspace Sharing](link)
## Detailed Design
### Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ API Gateway │
└────────────────────────┬────────────────────────────────────┘
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Workspace │ │ Sharing │ │ Auth │
│ Service │ │ Service │ │ Service │
│ (existing) │ │ (new) │ │ (existing) │
└──────┬──────┘ └──────┬──────┘ └─────────────┘
│ │
│ ┌──────┴──────┐
│ │ │
▼ ▼ ▼
┌─────────────────────┐ ┌─────────────┐
│ PostgreSQL │ │ Redis │
│ (permissions) │ │ (cache) │
└─────────────────────┘ └─────────────┘
### Component Responsibilities
| Component | Responsibility |
|-----------|----------------|
| **Sharing Service** | Invitation CRUD, permission management |
| **Workspace Service** | Add permission checks to existing endpoints |
| **Auth Service** | Issue tokens with workspace claims |
| **Redis** | Cache permission lookups |
### Permission Model
Three permission levels (bitmask for efficient storage):
| Level | Value | Capabilities |
|-------|-------|--------------|
| Viewer | 1 | Read workspace, view history |
| Editor | 3 | Viewer + create/edit/delete content |
| Owner | 7 | Editor + manage members, settings, delete workspace |
Permission inheritance:
- Owner > Editor > Viewer
- Each level includes all lower permissions
### Invitation Flow
1. Owner submits invitation request (email, permission level)
2. Sharing Service validates:
- Owner has permission
- Email format valid
- Workspace not at member limit
3. Generate invitation token (cryptographic random, 32 bytes)
4. Store invitation in pending_invitations table
5. Queue email via existing notification service
6. Invitee clicks link → validates token → creates membership
7. Token invalidated after use or expiration (7 days)
### Permission Check Flow
On every workspace request:
1. Extract workspace_id from request
2. Check Redis cache: `workspace:{id}:user:{user_id}`
3. If miss → query PostgreSQL → cache for 5 minutes
4. Deny if no permission record exists
5. Check operation against permission level
6. Log access attempt (success/failure)
Performance target: <10ms for cached, <50ms for uncached
## Data Model
### New Tables
-- Workspace memberships
CREATE TABLE workspace_memberships (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
permission_level SMALLINT NOT NULL DEFAULT 1,
invited_by UUID REFERENCES users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(workspace_id, user_id)
);
CREATE INDEX idx_memberships_workspace ON workspace_memberships(workspace_id);
CREATE INDEX idx_memberships_user ON workspace_memberships(user_id);
-- Pending invitations
CREATE TABLE workspace_invitations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
email VARCHAR(255) NOT NULL,
permission_level SMALLINT NOT NULL DEFAULT 1,
token VARCHAR(64) NOT NULL UNIQUE,
invited_by UUID NOT NULL REFERENCES users(id),
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
accepted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_invitations_token ON workspace_invitations(token);
CREATE INDEX idx_invitations_workspace ON workspace_invitations(workspace_id);
### Migration Strategy
1. Create new tables (non-blocking)
2. Backfill existing workspace owners into memberships table
3. Deploy permission checks in shadow mode (log but don't enforce)
4. Verify no legitimate access would be blocked
5. Enable enforcement with feature flag
## API Design
See [api-specs.md] for full OpenAPI specification.
Key endpoints:
- POST /workspaces/{id}/invitations - Create invitation
- GET /workspaces/{id}/members - List members
- PATCH /workspaces/{id}/members/{user_id} - Update permission
- DELETE /workspaces/{id}/members/{user_id} - Remove member
## Security Considerations
### Authentication
- All endpoints require valid JWT
- Invitation tokens are single-use, time-limited
### Authorization
- Permission checks on every workspace operation
- Owner-only operations: invite, remove, change permissions, delete workspace
- Audit log of all permission changes
### Data Protection
- Email addresses encrypted at rest
- Invitation tokens hashed in database
- Rate limiting: 10 invitations per hour per workspace
### Compliance
- GDPR: Include membership data in export/deletion
- SOC2: Audit trail requirements met
## Observability
### Metrics
- `sharing.invitations.sent` - Counter, by workspace
- `sharing.invitations.accepted` - Counter
- `sharing.permission_checks` - Histogram, by result (allowed/denied)
- `sharing.cache_hit_rate` - Gauge
### Logging
- All permission changes logged with actor, target, before/after
- Failed permission checks logged with request context
### Alerts
- Cache hit rate <80% for 5 minutes
- Permission check latency p99 >100ms
- Invitation accept rate <50% over 24 hours
## Rollout Plan
| Phase | Audience | Duration | Success Criteria |
|-------|----------|----------|------------------|
| Alpha | Internal team | 1 week | No blockers |
| Beta | 5% of Teams plan | 2 weeks | <0.1% error rate |
| GA | 100% | 1 week ramp | Metrics nominal |
Feature flag: `workspace_sharing_enabled`
Kill switch: Disable sharing service, fallback to owner-only access
## Alternatives Considered
### 1. Extend existing auth service
**Rejected:** Auth service is critical path, don't want to add complexity.
Separate service allows independent scaling and deployment.
### 2. Real-time permission sync (websockets)
**Rejected:** Adds complexity without clear user benefit.
5-minute cache TTL is acceptable for permission propagation.
### 3. Document-level permissions
**Rejected:** Out of scope for v1. Workspace-level granularity sufficient
based on user research.
## Open Questions
- [ ] Rate limit for invitations per workspace? (Proposed: 50/day)
- [ ] Allow users to leave workspaces? (Leaning yes)
- [ ] Notification when permissions changed? (Needs PM input)
## References
- [PRD: Team Workspace Sharing](link)
- [RFC: Permission System Evolution](link)
- [Auth Service Documentation](link)
Bad Technical Spec Example
# Tech Spec: Sharing
We need to add sharing to workspaces.
## Design
Add a new table for permissions. Add API endpoints for sharing.
Use Redis for caching.
## Security
Make it secure.
## Rollout
Deploy when ready.
Why it fails:
- No context or goals
- No architecture diagram
- Missing data model details
- No API contracts
- Vague security section
- No rollout strategy
- No alternatives considered
Technical Spec Review Checklist
Architecture
├── □ Clear component diagram
├── □ Responsibilities well-defined
├── □ Integration points identified
├── □ Dependencies documented
└── □ Scalability considered
Data Model
├── □ Schema defined with types
├── □ Indexes specified
├── □ Migration strategy clear
└── □ Backwards compatibility addressed
API Design
├── □ Endpoints documented
├── □ Request/response formats
├── □ Error handling defined
└── □ Versioning strategy
Security
├── □ Auth/authz approach
├── □ Data protection
├── □ Threat model considered
└── □ Compliance requirements
Operational
├── □ Metrics defined
├── □ Logging strategy
├── □ Alerting thresholds
├── □ Runbook considerations
└── □ Rollback plan
Process
├── □ Reviewed by stakeholders
├── □ Open questions resolved
├── □ Alternatives documented
└── □ Timeline realistic
Anti-Patterns
- Design by committee — Spec becomes vague to accommodate all opinions
- Premature optimization — Designing for scale you don't have yet
- Missing context — Spec without PRD link or business justification
- Implementation masquerading — Writing code in spec instead of design
- Solo authorship — No review from affected teams
- Scope creep — Spec expands to cover "nice to haves"
- Analysis paralysis — Perfect spec that never ships
- Dead doc — Spec not updated as implementation diverges