feat: Add TDD demo story and implementation structure

Add example story for User Email Validation TDD workflow:
- Complete story with acceptance criteria in Gherkin format
- Technical requirements and test plan with test IDs
- TDD phase progress tracking (currently red)
- Implementation tasks for Dev agent
- Directory structure for JS and Python demo implementations

This demo story provides teams with a practical example to reproduce
the red-green-refactor TDD cycle using BMAD framework and methodology.
This commit is contained in:
vforvaick 2025-09-01 21:16:27 +07:00
parent 173453636a
commit 6f109064e6
3 changed files with 945 additions and 0 deletions

393
bmad-core/scripts/tdd-guard.sh Executable file
View File

@ -0,0 +1,393 @@
#!/bin/bash
# TDD Guard - Validates that code changes follow TDD discipline
# Part of BMAD Framework TDD integration
set -e
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
CONFIG_FILE="${PROJECT_ROOT}/bmad-core/core-config.yaml"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Default values
TDD_ENABLED="false"
ALLOW_RED_PHASE_FAILURES="true"
EXIT_CODE=0
# Usage information
usage() {
cat << EOF
TDD Guard - Validates TDD discipline in code changes
Usage: $0 [options]
Options:
-h, --help Show this help message
-c, --config PATH Path to BMAD core config file
-b, --base REF Base commit/branch for comparison (default: HEAD~1)
-v, --verbose Verbose output
--phase PHASE Current TDD phase: red|green|refactor
--ci Running in CI mode (affects exit behavior)
--dry-run Show what would be checked without failing
Examples:
$0 # Check changes against HEAD~1
$0 --base main # Check changes against main branch
$0 --phase green # Validate green phase rules
$0 --ci --phase red # CI mode, red phase (allows failures)
Exit Codes:
0 No TDD violations found
1 TDD violations found (in green phase)
2 Configuration error
3 Git/repository error
EOF
}
# Logging functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
# Parse command line arguments
BASE_REF="HEAD~1"
VERBOSE=false
TDD_PHASE=""
CI_MODE=false
DRY_RUN=false
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
usage
exit 0
;;
-c|--config)
CONFIG_FILE="$2"
shift 2
;;
-b|--base)
BASE_REF="$2"
shift 2
;;
-v|--verbose)
VERBOSE=true
shift
;;
--phase)
TDD_PHASE="$2"
shift 2
;;
--ci)
CI_MODE=true
shift
;;
--dry-run)
DRY_RUN=true
shift
;;
*)
log_error "Unknown option: $1"
usage
exit 2
;;
esac
done
# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
log_error "Not in a git repository"
exit 3
fi
# Load configuration
load_config() {
if [[ ! -f "$CONFIG_FILE" ]]; then
if [[ "$VERBOSE" == true ]]; then
log_warn "Config file not found: $CONFIG_FILE"
log_info "Assuming TDD disabled"
fi
return 0
fi
# Extract TDD settings from YAML (basic parsing)
if command -v yq > /dev/null 2>&1; then
TDD_ENABLED=$(yq e '.tdd.enabled // false' "$CONFIG_FILE" 2>/dev/null || echo "false")
ALLOW_RED_PHASE_FAILURES=$(yq e '.tdd.allow_red_phase_ci_failures // true' "$CONFIG_FILE" 2>/dev/null || echo "true")
else
# Fallback: basic grep parsing
if grep -q "tdd:" "$CONFIG_FILE" && grep -A 10 "tdd:" "$CONFIG_FILE" | grep -q "enabled: true"; then
TDD_ENABLED="true"
fi
fi
if [[ "$VERBOSE" == true ]]; then
log_info "TDD enabled: $TDD_ENABLED"
log_info "Allow red phase failures: $ALLOW_RED_PHASE_FAILURES"
fi
}
# Detect TDD phase from commit messages or branch name
detect_tdd_phase() {
if [[ -n "$TDD_PHASE" ]]; then
return 0
fi
# Check recent commit messages for TDD phase indicators
RECENT_COMMITS=$(git log --oneline -5 "$BASE_REF".."HEAD" 2>/dev/null || echo "")
if echo "$RECENT_COMMITS" | grep -qi "\[RED\]"; then
TDD_PHASE="red"
elif echo "$RECENT_COMMITS" | grep -qi "\[GREEN\]"; then
TDD_PHASE="green"
elif echo "$RECENT_COMMITS" | grep -qi "\[REFACTOR\]"; then
TDD_PHASE="refactor"
else
# Try to detect from branch name
BRANCH_NAME=$(git branch --show-current 2>/dev/null || echo "")
if echo "$BRANCH_NAME" | grep -qi "tdd"; then
TDD_PHASE="green" # Default assumption
fi
fi
if [[ "$VERBOSE" == true ]]; then
log_info "Detected TDD phase: ${TDD_PHASE:-unknown}"
fi
}
# Get changed files between base and current
get_changed_files() {
# Get list of changed files
CHANGED_FILES=$(git diff --name-only "$BASE_REF"..."HEAD" 2>/dev/null || echo "")
if [[ -z "$CHANGED_FILES" ]]; then
if [[ "$VERBOSE" == true ]]; then
log_info "No changed files detected"
fi
return 0
fi
# Separate source and test files
SOURCE_FILES=""
TEST_FILES=""
while IFS= read -r file; do
if [[ -f "$file" ]]; then
if is_test_file "$file"; then
TEST_FILES="$TEST_FILES$file"$'\n'
elif is_source_file "$file"; then
SOURCE_FILES="$SOURCE_FILES$file"$'\n'
fi
fi
done <<< "$CHANGED_FILES"
if [[ "$VERBOSE" == true ]]; then
log_info "Source files changed: $(echo "$SOURCE_FILES" | wc -l | tr -d ' ')"
log_info "Test files changed: $(echo "$TEST_FILES" | wc -l | tr -d ' ')"
fi
}
# Check if file is a test file
is_test_file() {
local file="$1"
# Common test file patterns
if [[ "$file" =~ \.(test|spec)\.(js|ts|py|go|java|cs)$ ]] || \
[[ "$file" =~ _test\.(py|go)$ ]] || \
[[ "$file" =~ Test\.(java|cs)$ ]] || \
[[ "$file" =~ tests?/ ]] || \
[[ "$file" =~ spec/ ]]; then
return 0
fi
return 1
}
# Check if file is a source file
is_source_file() {
local file="$1"
# Common source file patterns (excluding test files)
if [[ "$file" =~ \.(js|ts|py|go|java|cs|rb|php|cpp|c|h)$ ]] && ! is_test_file "$file"; then
return 0
fi
return 1
}
# Check if commit message indicates refactoring
is_refactor_commit() {
local commits=$(git log --oneline "$BASE_REF".."HEAD" 2>/dev/null || echo "")
if echo "$commits" | grep -qi "\[refactor\]"; then
return 0
fi
return 1
}
# Validate TDD rules
validate_tdd_rules() {
local violations=0
if [[ -z "$SOURCE_FILES" && -z "$TEST_FILES" ]]; then
if [[ "$VERBOSE" == true ]]; then
log_info "No relevant source or test files changed"
fi
return 0
fi
case "$TDD_PHASE" in
"red")
# Red phase: Tests should be added/modified, minimal or no source changes
if [[ -n "$SOURCE_FILES" ]] && [[ -z "$TEST_FILES" ]]; then
log_warn "RED phase violation: Source code changed without corresponding test changes"
log_warn "In TDD Red phase, tests should be written first"
if [[ "$ALLOW_RED_PHASE_FAILURES" == "false" ]] || [[ "$CI_MODE" == "false" ]]; then
violations=$((violations + 1))
fi
fi
;;
"green")
# Green phase: Source changes must have corresponding test changes
if [[ -n "$SOURCE_FILES" ]] && [[ -z "$TEST_FILES" ]]; then
log_error "GREEN phase violation: Source code changed without corresponding tests"
log_error "In TDD Green phase, implementation should only make existing tests pass"
log_error "Source files modified:"
echo "$SOURCE_FILES" | while IFS= read -r file; do
[[ -n "$file" ]] && log_error " - $file"
done
violations=$((violations + 1))
fi
# Check for large changes (potential feature creep)
if [[ -n "$SOURCE_FILES" ]]; then
local large_changes=0
while IFS= read -r file; do
if [[ -n "$file" ]] && [[ -f "$file" ]]; then
local additions=$(git diff --numstat "$BASE_REF" "$file" | cut -f1)
if [[ "$additions" =~ ^[0-9]+$ ]] && [[ "$additions" -gt 50 ]]; then
log_warn "Large change detected in $file: $additions lines added"
log_warn "Consider smaller, more focused changes in TDD Green phase"
large_changes=$((large_changes + 1))
fi
fi
done <<< "$SOURCE_FILES"
if [[ "$large_changes" -gt 0 ]]; then
log_warn "Consider breaking large changes into smaller TDD cycles"
fi
fi
;;
"refactor")
# Refactor phase: Source changes allowed, tests should remain stable
if is_refactor_commit; then
if [[ "$VERBOSE" == true ]]; then
log_info "Refactor phase: Changes detected with proper [REFACTOR] tag"
fi
else
if [[ -n "$SOURCE_FILES" ]] && [[ -z "$TEST_FILES" ]]; then
log_warn "Potential refactor phase: Consider tagging commits with [REFACTOR]"
fi
fi
;;
*)
# Unknown or no TDD phase
if [[ "$TDD_ENABLED" == "true" ]]; then
log_warn "TDD enabled but phase not detected"
log_warn "Consider tagging commits with [RED], [GREEN], or [REFACTOR]"
if [[ -n "$SOURCE_FILES" ]] && [[ -z "$TEST_FILES" ]]; then
log_warn "Source changes without test changes - may violate TDD discipline"
fi
fi
;;
esac
return $violations
}
# Main execution
main() {
if [[ "$VERBOSE" == true ]]; then
log_info "TDD Guard starting..."
log_info "Base reference: $BASE_REF"
log_info "Config file: $CONFIG_FILE"
fi
load_config
if [[ "$TDD_ENABLED" != "true" ]]; then
if [[ "$VERBOSE" == true ]]; then
log_info "TDD not enabled, skipping validation"
fi
exit 0
fi
detect_tdd_phase
get_changed_files
if [[ "$DRY_RUN" == true ]]; then
log_info "DRY RUN - Would check:"
log_info " TDD Phase: ${TDD_PHASE:-unknown}"
log_info " Source files: $(echo "$SOURCE_FILES" | grep -c . || echo 0)"
log_info " Test files: $(echo "$TEST_FILES" | grep -c . || echo 0)"
exit 0
fi
validate_tdd_rules
local violations=$?
if [[ "$violations" -eq 0 ]]; then
log_success "TDD validation passed"
exit 0
else
log_error "$violations TDD violation(s) found"
# Provide helpful suggestions
echo ""
echo "💡 TDD Suggestions:"
case "$TDD_PHASE" in
"green")
echo " - Ensure all source changes have corresponding failing tests first"
echo " - Consider running QA agent's *write-failing-tests command"
echo " - Keep implementation minimal - only make tests pass"
;;
"red")
echo " - Write failing tests before implementation"
echo " - Use QA agent to create test cases first"
;;
*)
echo " - Follow TDD Red-Green-Refactor cycle"
echo " - Tag commits with [RED], [GREEN], or [REFACTOR]"
echo " - Enable TDD workflow in BMAD configuration"
;;
esac
echo ""
if [[ "$TDD_PHASE" == "red" ]] && [[ "$ALLOW_RED_PHASE_FAILURES" == "true" ]] && [[ "$CI_MODE" == "true" ]]; then
log_warn "Red phase violations allowed in CI mode"
exit 0
fi
exit 1
fi
}
# Run main function
main "$@"

View File

@ -0,0 +1,351 @@
# TDD-Enhanced CI/CD Workflow Template for BMAD Framework
# This template shows how to integrate TDD validation into CI/CD pipelines
name: TDD-Enhanced CI/CD
on:
push:
branches: [ main, develop, 'feature/tdd-*' ]
pull_request:
branches: [ main, develop ]
env:
# TDD Configuration
TDD_ENABLED: true
TDD_ALLOW_RED_PHASE_FAILURES: true
TDD_COVERAGE_THRESHOLD: 80
jobs:
# Detect TDD phase and validate changes
tdd-validation:
name: TDD Phase Validation
runs-on: ubuntu-latest
outputs:
tdd-phase: ${{ steps.detect-phase.outputs.phase }}
tdd-enabled: ${{ steps.detect-phase.outputs.enabled }}
should-run-tests: ${{ steps.detect-phase.outputs.should-run-tests }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Need full history for TDD guard
- name: Detect TDD phase
id: detect-phase
run: |
# Check if TDD is enabled in bmad-core/core-config.yaml
if grep -q "enabled: true" bmad-core/core-config.yaml 2>/dev/null; then
echo "enabled=true" >> $GITHUB_OUTPUT
echo "should-run-tests=true" >> $GITHUB_OUTPUT
else
echo "enabled=false" >> $GITHUB_OUTPUT
echo "should-run-tests=true" >> $GITHUB_OUTPUT # Run tests anyway
exit 0
fi
# Detect TDD phase from commit messages
COMMITS=$(git log --oneline -10 ${{ github.event.before }}..${{ github.sha }} || git log --oneline -10)
if echo "$COMMITS" | grep -qi "\[RED\]"; then
echo "phase=red" >> $GITHUB_OUTPUT
elif echo "$COMMITS" | grep -qi "\[GREEN\]"; then
echo "phase=green" >> $GITHUB_OUTPUT
elif echo "$COMMITS" | grep -qi "\[REFACTOR\]"; then
echo "phase=refactor" >> $GITHUB_OUTPUT
else
# Default phase detection based on branch
if [[ "${{ github.ref }}" =~ tdd ]]; then
echo "phase=green" >> $GITHUB_OUTPUT
else
echo "phase=unknown" >> $GITHUB_OUTPUT
fi
fi
- name: Run TDD Guard
if: steps.detect-phase.outputs.enabled == 'true'
run: |
echo "🧪 Running TDD Guard validation..."
# Make TDD guard executable
chmod +x bmad-core/scripts/tdd-guard.sh
# Run TDD guard with appropriate settings
if [[ "${{ steps.detect-phase.outputs.phase }}" == "red" ]]; then
# Allow red phase failures in CI
./bmad-core/scripts/tdd-guard.sh --ci --phase red --verbose || {
echo "⚠️ Red phase violations detected but allowed in CI"
exit 0
}
else
# Strict validation for green/refactor phases
./bmad-core/scripts/tdd-guard.sh --phase "${{ steps.detect-phase.outputs.phase }}" --verbose
fi
# Test execution with TDD awareness
test:
name: Run Tests
runs-on: ubuntu-latest
needs: tdd-validation
if: needs.tdd-validation.outputs.should-run-tests == 'true'
strategy:
matrix:
# Add multiple language support as needed
language: [javascript, python]
include:
- language: javascript
test-command: npm test
coverage-command: npm run test:coverage
setup: |
node-version: 18
cache: npm
- language: python
test-command: pytest
coverage-command: pytest --cov=.
setup: |
python-version: '3.9'
cache: pip
steps:
- name: Checkout code
uses: actions/checkout@v4
# Language-specific setup
- name: Setup Node.js
if: matrix.language == 'javascript'
uses: actions/setup-node@v4
with:
node-version: 18
cache: 'npm'
- name: Setup Python
if: matrix.language == 'python'
uses: actions/setup-python@v4
with:
python-version: '3.9'
cache: 'pip'
# Install dependencies
- name: Install JavaScript dependencies
if: matrix.language == 'javascript'
run: |
if [ -f package.json ]; then
npm ci
fi
- name: Install Python dependencies
if: matrix.language == 'python'
run: |
if [ -f requirements.txt ]; then
pip install -r requirements.txt
fi
if [ -f requirements-dev.txt ]; then
pip install -r requirements-dev.txt
fi
# Run tests with TDD phase awareness
- name: Run tests
id: run-tests
run: |
echo "🧪 Running tests for TDD phase: ${{ needs.tdd-validation.outputs.tdd-phase }}"
case "${{ needs.tdd-validation.outputs.tdd-phase }}" in
"red")
echo "RED phase: Expecting some tests to fail"
${{ matrix.test-command }} || {
echo "⚠️ Tests failed as expected in RED phase"
if [[ "$TDD_ALLOW_RED_PHASE_FAILURES" == "true" ]]; then
echo "test-result=red-expected-fail" >> $GITHUB_OUTPUT
exit 0
else
echo "test-result=fail" >> $GITHUB_OUTPUT
exit 1
fi
}
echo "test-result=pass" >> $GITHUB_OUTPUT
;;
"green"|"refactor")
echo "GREEN/REFACTOR phase: All tests should pass"
${{ matrix.test-command }}
echo "test-result=pass" >> $GITHUB_OUTPUT
;;
*)
echo "Unknown phase: Running standard test suite"
${{ matrix.test-command }}
echo "test-result=pass" >> $GITHUB_OUTPUT
;;
esac
# Generate coverage report
- name: Generate coverage report
if: env.TDD_COVERAGE_THRESHOLD > 0
run: |
echo "📊 Generating coverage report..."
${{ matrix.coverage-command }} || echo "Coverage command failed"
# Upload coverage reports
- name: Upload coverage to Codecov
if: matrix.language == 'javascript' || matrix.language == 'python'
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml
flags: ${{ matrix.language }}
name: ${{ matrix.language }}-coverage
fail_ci_if_error: false
# Quality gates specific to TDD phase
quality-gates:
name: Quality Gates
runs-on: ubuntu-latest
needs: [tdd-validation, test]
if: always()
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: TDD Phase Quality Gate
run: |
echo "🚦 Evaluating quality gates for TDD phase: ${{ needs.tdd-validation.outputs.tdd-phase }}"
case "${{ needs.tdd-validation.outputs.tdd-phase }}" in
"red")
echo "RED phase quality gate:"
echo "✅ Tests written first"
echo "✅ Implementation minimal or non-existent"
if [[ "${{ needs.test.result }}" == "success" ]] || [[ "${{ needs.test.outputs.test-result }}" == "red-expected-fail" ]]; then
echo "✅ RED phase gate: PASS"
else
echo "❌ RED phase gate: FAIL"
exit 1
fi
;;
"green")
echo "GREEN phase quality gate:"
echo "✅ All tests passing"
echo "✅ Minimal implementation"
echo "✅ No feature creep"
if [[ "${{ needs.test.result }}" == "success" ]]; then
echo "✅ GREEN phase gate: PASS"
else
echo "❌ GREEN phase gate: FAIL"
exit 1
fi
;;
"refactor")
echo "REFACTOR phase quality gate:"
echo "✅ Tests remain green"
echo "✅ Code quality improved"
echo "✅ Behavior preserved"
if [[ "${{ needs.test.result }}" == "success" ]]; then
echo "✅ REFACTOR phase gate: PASS"
else
echo "❌ REFACTOR phase gate: FAIL"
exit 1
fi
;;
*)
echo "Standard quality gate:"
if [[ "${{ needs.test.result }}" == "success" ]]; then
echo "✅ Standard gate: PASS"
else
echo "❌ Standard gate: FAIL"
exit 1
fi
;;
esac
- name: Generate TDD Report
if: needs.tdd-validation.outputs.tdd-enabled == 'true'
run: |
echo "# TDD Pipeline Report" > tdd-report.md
echo "" >> tdd-report.md
echo "**TDD Phase:** ${{ needs.tdd-validation.outputs.tdd-phase }}" >> tdd-report.md
echo "**Test Result:** ${{ needs.test.outputs.test-result || 'unknown' }}" >> tdd-report.md
echo "**Quality Gate:** $([ "${{ job.status }}" == "success" ] && echo "PASS" || echo "FAIL")" >> tdd-report.md
echo "" >> tdd-report.md
echo "## Phase-Specific Results" >> tdd-report.md
case "${{ needs.tdd-validation.outputs.tdd-phase }}" in
"red")
echo "- ✅ Failing tests written first" >> tdd-report.md
echo "- ✅ Implementation postponed until GREEN phase" >> tdd-report.md
;;
"green")
echo "- ✅ Tests now passing" >> tdd-report.md
echo "- ✅ Minimal implementation completed" >> tdd-report.md
;;
"refactor")
echo "- ✅ Code quality improved" >> tdd-report.md
echo "- ✅ All tests remain green" >> tdd-report.md
;;
esac
- name: Comment TDD Report on PR
if: github.event_name == 'pull_request' && needs.tdd-validation.outputs.tdd-enabled == 'true'
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
if (fs.existsSync('tdd-report.md')) {
const report = fs.readFileSync('tdd-report.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## 🧪 TDD Pipeline Results\n\n${report}`
});
}
# Deploy only after successful TDD validation
deploy:
name: Deploy
runs-on: ubuntu-latest
needs: [tdd-validation, test, quality-gates]
if: github.ref == 'refs/heads/main' && success()
steps:
- name: Deploy Application
run: |
echo "🚀 Deploying application after successful TDD validation"
echo "TDD Phase: ${{ needs.tdd-validation.outputs.tdd-phase }}"
# Add your deployment steps here
# Only deploy if all TDD phases pass validation
if [[ "${{ needs.tdd-validation.outputs.tdd-phase }}" == "green" ]] || [[ "${{ needs.tdd-validation.outputs.tdd-phase }}" == "refactor" ]]; then
echo "✅ Safe to deploy: Implementation complete and tested"
else
echo "⚠️ Deployment skipped: Not in a stable TDD phase"
exit 0
fi
# Additional workflow for TDD metrics collection
tdd-metrics:
name: TDD Metrics
runs-on: ubuntu-latest
needs: [tdd-validation, test, quality-gates]
if: always() && needs.tdd-validation.outputs.tdd-enabled == 'true'
steps:
- name: Collect TDD Metrics
run: |
echo "📊 Collecting TDD metrics..."
# Calculate TDD cycle time (example)
CYCLE_START=$(git log --grep="\[RED\]" --format="%ct" -1 || echo $(date +%s))
CYCLE_END=$(date +%s)
CYCLE_TIME=$(( (CYCLE_END - CYCLE_START) / 60 )) # minutes
echo "TDD Cycle Metrics:"
echo "- Phase: ${{ needs.tdd-validation.outputs.tdd-phase }}"
echo "- Cycle Time: ${CYCLE_TIME} minutes"
echo "- Test Status: ${{ needs.test.outputs.test-result }}"
echo "- Quality Gate: $([ "${{ needs.quality-gates.result }}" == "success" ] && echo "PASS" || echo "FAIL")"
# Store metrics (example - adapt to your metrics system)
echo "Metrics would be stored in your preferred system (Grafana, etc.)"

View File

@ -0,0 +1,201 @@
# Story 1.1: User Email Validation
## Story Metadata
```yaml
story:
epic: '1'
number: '1'
title: 'User Email Validation'
status: 'ready'
priority: 'high'
# TDD Configuration
tdd:
status: 'red' # Current phase: red|green|refactor|done
cycle: 1
coverage_target: 90.0
tests:
- id: 'UV-001'
name: 'should validate correct email format'
type: unit
status: failing
file_path: 'tests/user-validator.test.js'
- id: 'UV-002'
name: 'should reject invalid email format'
type: unit
status: failing
file_path: 'tests/user-validator.test.js'
- id: 'UV-003'
name: 'should handle edge cases'
type: unit
status: failing
file_path: 'tests/user-validator.test.js'
```
## Story Description
**As a** System Administrator
**I want** to validate user email addresses
**So that** only users with valid email formats can register
### Context
This is a foundational feature for user registration. We need robust email validation that follows RFC standards while being user-friendly. This will be used by the registration system and user profile updates.
## Acceptance Criteria
```gherkin
Feature: User Email Validation
Scenario: Valid email formats are accepted
Given a user provides an email address
When the email has correct format with @ symbol and domain
Then the validation should return true
Scenario: Invalid email formats are rejected
Given a user provides an invalid email address
When the email lacks @ symbol or proper domain format
Then the validation should return false with appropriate error message
Scenario: Edge cases are handled properly
Given a user provides edge case email formats
When validation is performed on emails with special characters or unusual formats
Then the system should handle them according to RFC standards
```
## Technical Requirements
### Functional Requirements
- Validate email format using RFC-compliant rules
- Return boolean result with error details when invalid
- Handle common edge cases (special characters, multiple @, etc.)
- Performance: validation should complete in < 1ms
### Non-Functional Requirements
- **Performance:** < 1ms validation time per email
- **Security:** Prevent injection attacks via email input
- **Reliability:** 99.9% accuracy on email format validation
- **Maintainability:** Clear error messages for debugging
## TDD Test Plan (QA Agent Responsibility)
### Test Strategy
- **Primary Test Type:** unit
- **Mocking Approach:** No external dependencies to mock
- **Test Data:** Fixed test cases covering valid/invalid formats
### Planned Test Scenarios
| ID | Scenario | Type | Priority | AC Reference |
| ------ | ---------------------------- | ---- | -------- | ------------ |
| UV-001 | Valid email formats accepted | unit | P0 | AC1 |
| UV-002 | Invalid formats rejected | unit | P0 | AC2 |
| UV-003 | Edge cases handled | unit | P1 | AC3 |
| UV-004 | Performance requirements met | unit | P2 | NFR |
## TDD Progress
### Current Phase: RED
**Cycle:** 1
**Last Updated:** 2025-01-12
### Red Phase - Cycle 1
**Date:** 2025-01-12
**Agent:** Quinn (QA Agent)
**Tests Written:**
- UV-001: should validate correct email format (FAILING ✅)
- UV-002: should reject invalid email format (FAILING ✅)
- UV-003: should handle edge cases (FAILING ✅)
**Test Files:**
- tests/user-validator.test.js
**Next Step:** Dev Agent to implement minimal code to make tests pass
---
## Implementation Tasks (Dev Agent)
### Primary Tasks
- [ ] Create UserValidator class
- [ ] Implement email validation logic
- [ ] Handle error cases and edge cases
### Subtasks
- [ ] Set up basic class structure
- [ ] Implement regex-based validation
- [ ] Add error message generation
- [ ] Performance optimization
## Definition of Done
### TDD-Specific DoD
- [ ] Tests written first (Red phase completed)
- [ ] All tests passing (Green phase completed)
- [ ] Code refactored for quality (Refactor phase completed)
- [ ] Test coverage meets target (90%)
- [ ] All external dependencies properly mocked (N/A for this story)
- [ ] No features implemented without corresponding tests
### General DoD
- [ ] All acceptance criteria met
- [ ] Code follows project standards
- [ ] Documentation updated
- [ ] Ready for review
## Dev Agent Record
### Implementation Notes
_(Dev agent will document implementation decisions here)_
### TDD Cycle Log
_(Automatic tracking of Red-Green-Refactor progression)_
**Cycle 1:**
- Red Phase: 2025-01-12 - 3 failing tests written
- Green Phase: _(pending)_
- Refactor Phase: _(pending)_
### File List
_(Dev agent will list all files created/modified)_
- tests/user-validator.test.js (created)
- _(implementation files will be added during GREEN phase)_
### Test Execution Log
```bash
# RED phase test runs will be logged here
```
## QA Results
_(QA agent will populate this during review)_
## Change Log
- **2025-01-12**: Story created from TDD template
- **2025-01-12**: Red phase completed - failing tests written
---
**TDD Status:** 🔴 RED Phase
**Agent Assigned:** Quinn (QA) → James (Dev)
**Estimated Effort:** 2 hours