Feature Validation Standards Guide
Status: Complete
Category: Critical Development Standards
Version: 1.0
Based On: V4 "Real Working Features" Philosophy
The Ultimate Test
"Show me the campaign you created"
V3 Answer: "Here's the UI where you would create it"
V4 Answer: "Here's campaign 18d63b82-5dcd-4e56-a066-8d1bd7a3a476 in the database"
Only V4 passes. This guide ensures you build V4 quality.
Table of Contents
- Core Philosophy
- Definition of "Working"
- Database-First Development
- Real Integration Testing
- Success Metrics
- Validation Protocols
- Common Anti-Patterns
- Implementation Checklist
Core Philosophy
Working > Perfect
The V4 Success Formula:
Database First β Real APIs β Real Integrations β Real Data β Real Value
Key Principles
- Real IDs Beat Mock Data: Every feature creates queryable database records
- Integration Errors Are Success: They prove the system is real
- Test with External Services Immediately: Discover real issues early
- Every Feature Needs a Database Table: No table = No feature
- Can a Customer Use It?: The only question that matters
Definition of "Working"
What "Working" Means
interface WorkingFeature {
// MANDATORY: All must be true
database: {
recordsCreated: boolean; // Real records exist
recordsQueryable: boolean; // Can SELECT and verify
recordsPersistent: boolean; // Survives restart
recordsHaveRealIds: boolean; // UUIDs, not "mock-123"
};
api: {
endpointResponds: boolean; // Returns real data
createsRealData: boolean; // Not mock responses
handlesErrors: boolean; // Graceful failures
returnsRealIds: boolean; // Traceable IDs
};
integration: {
externalServiceCalled: boolean; // Actually connects
realResponseReceived: boolean; // Not mocked
errorsAreReal: boolean; // "Domain not verified" = good!
dataFlowsThrough: boolean; // End-to-end works
};
user: {
canDemonstrateFeature: boolean; // Show actual result
dataIsVerifiable: boolean; // Can query and confirm
valueIsDelivered: boolean; // Solves real problem
};
}
Concrete Examples
NOT Working (V3 Style)
// Returns mock data
async function createCampaign(data) {
return {
id: "mock-campaign-123",
status: "created"
};
}
WORKING (V4 Style)
// Creates real database record
async function createCampaign(data) {
const result = await db.query(
'INSERT INTO campaigns (name, config) VALUES ($1, $2) RETURNING id',
[data.name, data.config]
);
return {
id: result.rows[0].id, // Real UUID: "18d63b82-5dcd-4e56-a066-8d1bd7a3a476"
status: "created"
};
}
// Proof it works:
// SELECT * FROM campaigns WHERE id = '18d63b82-5dcd-4e56-a066-8d1bd7a3a476';
// Returns actual data!
Database-First Development
The V4 Approach: Create Before You Need
-- STEP 1: Create tables FIRST (before any UI)
CREATE TABLE campaigns (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL,
name VARCHAR(255) NOT NULL,
status VARCHAR(50) DEFAULT 'draft',
config JSONB DEFAULT '{}',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE contacts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL,
email VARCHAR(255) NOT NULL,
first_name VARCHAR(100),
last_name VARCHAR(100),
tags TEXT[] DEFAULT '{}',
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE email_deliveries (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
campaign_id UUID REFERENCES campaigns(id),
contact_id UUID REFERENCES contacts(id),
status VARCHAR(50),
delivered_at TIMESTAMP,
opened_at TIMESTAMP,
clicked_at TIMESTAMP
);
Validation: Tables Exist Before Features
// MANDATORY: Run before starting feature development
async function validateDatabaseReady(): Promise<boolean> {
const requiredTables = [
'campaigns',
'contacts',
'email_deliveries',
'organizations',
'users'
];
for (const table of requiredTables) {
const exists = await db.query(
"SELECT EXISTS (SELECT FROM pg_tables WHERE tablename = $1)",
[table]
);
if (!exists.rows[0].exists) {
throw new Error(`Missing required table: ${table}`);
}
}
return true;
}
Real Integration Testing
Test with Real Services Immediately
// β WRONG: Mock service for "later"
class EmailService {
async send(email) {
console.log('Would send email:', email);
return { success: true, messageId: 'mock-123' };
}
}
// β
RIGHT: Real service from day one
class EmailService {
async send(email) {
try {
const response = await fetch('https://api.postmarkapp.com/email', {
method: 'POST',
headers: {
'X-Postmark-Server-Token': process.env.POSTMARK_TOKEN,
'Content-Type': 'application/json'
},
body: JSON.stringify(email)
});
const result = await response.json();
// Real error? GOOD! We learned something
if (result.ErrorCode) {
console.log('Integration insight:', result.Message);
// "Sender signature not verified" tells us what to fix!
}
return result;
} catch (error) {
// Real integration errors guide next steps
console.log('Real issue discovered:', error);
throw error;
}
}
}
Integration Validation Checklist
interface IntegrationValidation {
service: string;
checks: {
canConnect: boolean; // Service responds
authWorks: boolean; // Credentials valid
canSendData: boolean; // API accepts our format
receivesResponse: boolean; // Get real response
errorsInformative: boolean; // Errors guide fixes
};
// Document real responses for proof
sampleResponse?: {
success?: any;
error?: any;
};
}
// Example validation result
const postmarkValidation: IntegrationValidation = {
service: 'Postmark',
checks: {
canConnect: true,
authWorks: true,
canSendData: true,
receivesResponse: true,
errorsInformative: true
},
sampleResponse: {
error: {
ErrorCode: 406,
Message: "Sender signature not verified"
// This real error taught us we need domain verification!
}
}
};
Success Metrics
Quantitative Validation
class FeatureValidator {
async validate(featureName: string): Promise<ValidationReport> {
const report = {
feature: featureName,
timestamp: new Date().toISOString(),
checks: {},
evidence: {}
};
// 1. Database Records Exist
const recordCount = await db.query(
'SELECT COUNT(*) FROM campaigns WHERE created_at > NOW() - INTERVAL \'1 hour\''
);
report.checks.hasRealData = recordCount.rows[0].count > 0;
// 2. API Endpoints Work
const apiTest = await fetch('/api/campaigns');
report.checks.apiResponds = apiTest.ok;
report.evidence.apiResponse = await apiTest.json();
// 3. Real IDs Generated
const campaign = await createTestCampaign();
report.checks.generatesRealIds = isValidUUID(campaign.id);
report.evidence.sampleId = campaign.id;
// 4. Data Persists
const retrieved = await db.query(
'SELECT * FROM campaigns WHERE id = $1',
[campaign.id]
);
report.checks.dataPersists = retrieved.rows.length > 0;
// 5. User Can Demonstrate
report.checks.userCanDemo = Object.values(report.checks)
.every(check => check === true);
return report;
}
}
Qualitative Validation
## Feature Validation Report
**Feature**: Campaign Creation
**Date**: 2025-08-03
**Validator**: Development Team
### Can a customer use it? β
YES
**Evidence**:
1. Created campaign with ID: `18d63b82-5dcd-4e56-a066-8d1bd7a3a476`
2. Campaign exists in database (verified via SELECT)
3. API returns real campaign data
4. Email integration attempted (got real error response)
5. Contact import successful (5 contacts added)
### Real IDs Generated:
- Campaign: `18d63b82-5dcd-4e56-a066-8d1bd7a3a476`
- Contact: `a7f3b291-8c54-4e89-b234-567890123456`
- User: `f855a22c-beed-4ed5-a14c-e7cabd2187f3`
### Integration Status:
- β
Database: Connected and storing data
- β οΈ Postmark: Connected but needs domain verification
- β
n8n: Workflows deployable via API
- β
Analytics: Returning real metrics
Validation Protocols
Daily Validation Routine
#!/bin/bash
# Daily feature validation script
echo "π― Daily Feature Validation"
echo "=========================="
# 1. Check database has real data
echo "1. Database Check:"
psql $DATABASE_URL -c "SELECT COUNT(*) as campaigns FROM campaigns;"
psql $DATABASE_URL -c "SELECT COUNT(*) as contacts FROM contacts;"
# 2. Test API endpoints
echo "2. API Check:"
curl -X GET http://localhost:3000/api/campaigns | jq .
curl -X GET http://localhost:3000/api/analytics | jq .
# 3. Verify specific IDs still exist
echo "3. Known ID Check:"
psql $DATABASE_URL -c "SELECT id, name FROM campaigns WHERE id = '18d63b82-5dcd-4e56-a066-8d1bd7a3a476';"
# 4. Test create operation
echo "4. Create Test:"
curl -X POST http://localhost:3000/api/campaigns \
-H "Content-Type: application/json" \
-d '{"name":"Daily Test Campaign"}' | jq .
echo "β
Validation Complete"
Per-Feature Validation
// Run for EVERY feature before marking complete
async function validateFeatureComplete(feature: string) {
const validations = [
checkDatabaseRecords,
checkApiEndpoints,
checkIntegrations,
checkUserFlow,
checkErrorHandling
];
const results = await Promise.all(
validations.map(v => v(feature))
);
const allPassed = results.every(r => r.passed);
if (!allPassed) {
const failures = results.filter(r => !r.passed);
throw new Error(
`Feature ${feature} validation failed:\n` +
failures.map(f => `- ${f.reason}`).join('\n')
);
}
// Generate proof document
await generateValidationProof(feature, results);
return true;
}
Common Anti-Patterns
Anti-Pattern 1: Mock-First Development
Wrong: Build with mocks, plan to add real data "later"
Right: Connect to real database from minute one
Why: "Later" never comes, mocks hide real issues
Anti-Pattern 2: Perfect Infrastructure First
Wrong: Spend days on perfect architecture with no features
Right: Create working features with simple architecture
Why: Working beats perfect every time
Anti-Pattern 3: UI Without Database
Wrong: Build beautiful UI that doesn't persist data
Right: Create database tables before UI
Why: UI without data is just a picture
Anti-Pattern 4: Avoiding External Services
Wrong: "We'll integrate Postmark after everything else works"
Right: Integrate Postmark in first iteration
Why: Integration errors teach valuable lessons early
Anti-Pattern 5: Untraceable Success Claims
Wrong: "The feature works!" (no evidence)
Right: "Campaign 18d63b82 exists in database" (provable)
Why: Concrete IDs are undeniable proof
Implementation Checklist
Before Starting Any Feature
- Database table created
- Migration script written and run
- Sample data inserted for testing
- Direct SQL query confirms table works
During Feature Development
- API endpoint creates real records
- Generated IDs are real UUIDs
- External service integration attempted
- Errors logged and learned from
- Data persistence verified
Before Marking Complete
- Specific ID documented as proof
- Database query shows real data
- API returns actual records
- User can demonstrate feature
- Integration errors documented
Validation Evidence Required
- Screenshot of database query result
- API response with real ID
- Integration attempt log (success or error)
- User demonstration video/screenshot
- Validation script output
Quick Validation Commands
# Prove your feature works with these commands:
# 1. Show me the record
psql $DATABASE_URL -c "SELECT * FROM [table] WHERE id = '[your-uuid]';"
# 2. Call the API
curl http://localhost:3000/api/[endpoint]/[your-uuid]
# 3. Count real records
psql $DATABASE_URL -c "SELECT COUNT(*) FROM [table] WHERE created_at > NOW() - INTERVAL '1 day';"
# 4. Show integration attempts
grep "Postmark\|n8n\|Stripe" logs/app.log | tail -20
# 5. Demonstrate persistence (restart and check)
docker-compose restart
psql $DATABASE_URL -c "SELECT * FROM [table] WHERE id = '[your-uuid]';"
Success Criteria
A feature is ONLY complete when:
Real Database Records
- Query returns actual data
- IDs are UUIDs, not mocks
Working API
- Endpoints return real data
- Errors are handled gracefully
Integration Attempted
- External service was called
- Real response (error or success) received
User Can Demo
- "Show me X" has a concrete answer
- Data survives restart
Evidence Documented
- Specific IDs recorded
- Validation output saved
Final Wisdom
"Working software is the primary measure of progress" - Agile Manifesto
This guide ensures you build WORKING software, not beautiful mockups.
Remember:
- Real IDs > Mock data
- Database records > UI promises
- Integration errors > No integration
- Concrete evidence > "Trust me it works"
- Customer value > Developer comfort
Based on V4's breakthrough realization: Features without real data are just expensive mockups. Build real value from day one.