| name | test-data-cleanup |
| description | Use after running tests to clean up test data. Analyzes tenant structure, identifies test-created tenants (empty shells), and safely removes only records with "Test" pattern. Always shows preview and requires confirmation before deletion. |
Test Data Cleanup Skill
Golden Rule
All test data MUST contain "Test" in the name or "@test." in email.
This ensures safe, pattern-based cleanup that never touches real data.
Tenant Structure (CRITICAL)
Production Tenant
- Volta (
11111111-1111-1111-1111-111111111111) - Main org with REAL data mixed with test data
- Contains: Real companies, contacts, Fireflies meetings, AND test forms/programs
Test-Created Tenants (Empty Shells)
Tests often create new tenants instead of using Volta. These are identifiable by:
- Timestamp in name:
Org A 1763320623066
- Generic test names:
Test, Organization A, Organization B
- All have 0 records - safe to delete entirely
Predefined Test Tenants (May Not Exist)
- Acme/Volta:
11111111-1111-1111-1111-111111111111
- Beta:
22222222-2222-2222-2222-222222222222
- Gamma:
33333333-3333-3333-3333-333333333333
Cleanup Strategy
Step 1: Analyze Tenant Structure
SELECT
t.name as tenant_name,
t.id as tenant_id,
CASE
WHEN t.id = '11111111-1111-1111-1111-111111111111' THEN 'VOLTA (Main)'
WHEN t.name ~ '\d{10,}' THEN 'TEST-CREATED (timestamp)'
WHEN t.name IN ('Test', 'Organization A', 'Organization B') THEN 'TEST-CREATED (generic)'
ELSE 'UNCLEAR'
END as tenant_type,
(SELECT COUNT(*) FROM companies c WHERE c.tenant_id = t.id) as companies,
(SELECT COUNT(*) FROM contacts co WHERE co.tenant_id = t.id) as contacts,
(SELECT COUNT(*) FROM forms f WHERE f.tenant_id = t.id) as forms
FROM tenants t
ORDER BY tenant_type, t.name;
Step 2: Delete Empty Test-Created Tenants
SELECT id, name FROM tenants
WHERE (name ~ '\d{10,}' OR name IN ('Test', 'Organization A', 'Organization B'))
AND id != '11111111-1111-1111-1111-111111111111'
AND id != '22222222-2222-2222-2222-222222222222'
AND id != '33333333-3333-3333-3333-333333333333';
DELETE FROM tenants WHERE id IN (...);
Step 3: Clean Test Data in Volta (Pattern-Based)
Only delete records with "Test" in name/title:
SELECT 'forms' as table_name, COUNT(*) FILTER (WHERE title ILIKE '%test%') as test_matches
FROM forms WHERE tenant_id = '11111111-1111-1111-1111-111111111111'
UNION ALL
SELECT 'programs', COUNT(*) FILTER (WHERE name ILIKE '%test%')
FROM programs WHERE tenant_id = '11111111-1111-1111-1111-111111111111'
UNION ALL
SELECT 'report_sessions', COUNT(*) FILTER (WHERE title ILIKE '%test%')
FROM report_sessions WHERE tenant_id = '11111111-1111-1111-1111-111111111111'
UNION ALL
SELECT 'companies', COUNT(*) FILTER (WHERE business_name ILIKE '%test%')
FROM companies WHERE tenant_id = '11111111-1111-1111-1111-111111111111';
Step 4: Delete Test Users
SELECT id, email FROM auth.users
WHERE email LIKE '%@test.%' OR email LIKE '%@example.%';
Tables to Clean (FK-Safe Order)
| Order | Table | Pattern Column | Query |
|---|
| 1 | forms | title | title ILIKE '%test%' |
| 2 | report_sessions | title | title ILIKE '%test%' |
| 3 | programs | name | name ILIKE '%test%' |
| 4 | companies | business_name | business_name ILIKE '%test%' |
| 5 | contacts | first_name/last_name | first_name ILIKE '%test%' OR last_name ILIKE '%test%' |
| 6 | user_sessions | (linked) | Delete for test users |
| 7 | organization_members | (linked) | Delete for test users |
| 8 | auth.users | email | email LIKE '%@test.%' |
| 9 | tenants | name | Empty test-created tenants |
Tables to NEVER Clean (Real Data)
| Table | Reason |
|---|
| fireflies_staged_meetings | Real imported meetings |
| meeting_transcripts | Real meeting data |
| interactions | Real meeting records |
| contacts (without Test) | Real people |
| companies (without Test) | Real businesses |
| reports | Real generated reports |
Naming Conventions (For Writing Tests)
Users/Emails
`test-feature-${Date.now()}@test.com`
`user-${Date.now()}@gmail.com`
Companies
`Test Company ${Date.now()}`
`Company A ${Date.now()}`
Contacts
{ first_name: 'Test', last_name: `User ${Date.now()}` }
{ first_name: 'Alice', last_name: 'Smith' }
Tenants
const tenantId = TEST_TENANT_ACME
const { data: tenant } = await adminClient.from('tenants').insert({ name: 'Org A' })
Agent Workflow
When asked to clean up test data:
- Analyze - Query tenant structure and data distribution
- Identify - Find test-created tenants and test pattern records
- Preview - Show summary table to user
- Confirm - Ask for explicit approval
- Delete - Execute in FK-safe order
- Report - Show results
Example Output
## Tenant Analysis
- Volta (main): 283 companies, 836 contacts, 318 Fireflies meetings
- Test-created tenants: 13 (all empty)
## Test Data in Volta
- Forms with "Test": 203
- Programs with "Test": 10
- Report sessions with "Test": 18
- Companies with "Test": 3
## Test Users
- @test.com/@example.com emails: 527
## Recommended Cleanup
1. Delete 13 empty test-created tenants
2. Delete 527 test users
3. Delete 203 test forms
4. Delete 10 test programs
5. Delete 18 test report sessions
6. Delete 3 test companies
Proceed? (y/n)
Test Helper Integration
Use __tests__/api/helpers.ts:
import {
createTestUser,
createTestCompany,
createTestContact,
createTestForm,
createTestReport,
countTestDataByPattern,
cleanupTestDataByPattern,
TEST_TENANT_ACME,
TEST_TENANT_BETA,
TEST_TENANT_GAMMA
} from '@/__tests__/api/helpers'
Common Issues
Issue: Tests create new tenants
Fix: Always use TEST_TENANT_ACME instead of creating new tenants
Issue: Test data doesn't have "Test" in name
Fix: Update test to use proper naming convention
Issue: Real data accidentally has "Test" in name
Check: Verify before deletion - this should be rare