Production Cleanup & Test Data Prevention Summary
**Date:** 2026-04-09
**Purpose:** Brennan incident recovery - Remove all test data except Brennan tenant
**Author:** Claude Code
---
๐จ EXECUTIVE SUMMARY
Your production database contains **1,829 tenants** with **3,658-18,290 agents**, most of which are test data. This document provides the tools and procedures to clean up the database and prevent future test data contamination.
**Brennan Tenant (Keep):**
- ID:
31c06fc4-db22-4740-83ea-48ac14f25810 - Name: Brennan Machinery
- Subdomain: brennan
---
๐ TABLE OF CONTENTS
---
๐ฏ IMMEDIATE ACTIONS
Step 1: Run Diagnostic Script
# Set database connection
export DATABASE_URL="postgresql://user:pass@host/db?sslmode=require"
# Run diagnostic
cd backend-saas
python3 scripts/diagnostic_prevent_test_data.py**What it does:**
- Detects tenants with
test_tenant=trueflag - Identifies suspicious name patterns (test, demo, sample)
- Flags suspicious email domains (test.com, example.com)
- Detects bulk creation patterns
- Finds abandoned/unused tenants
- Provides cleanup recommendations
**Output:** JSON report saved to /tmp/production_diagnostic_*.json
---
๐งน CLEANUP PROCEDURE
Step 2: Execute Cleanup Script
โ ๏ธ **CRITICAL:** Read the safety guide before running!
# Set environment variables
export DATABASE_URL="postgresql://user:pass@host/db?sslmode=require"
export REDIS_URL="rediss://quiet-monkey-21389.upstash.io:6379"
export KEEP_TENANT_ID="31c06fc4-db22-4740-83ea-48ac14f25810"
export CONFIRM_CLEANUP="YES_I_UNDERSTAND_THIS_WILL_DELETE_ALL_TENANTS_EXCEPT_KEEP_TENANT"
# Run cleanup
cd backend-saas
python3 scripts/cleanup_all_tenants_except_brennan.py**What it deletes (in order):**
- **Level 1: Dependent Data**
- Episodes, feedback, skills, capabilities
- Agent usage records, metrics
- Conversations, messages, sessions
- Canvas audits, snapshots, skills
- Integration connections, webhooks, credentials
- Marketplace submissions, reviews
- Usage records, quotas
- Proposals, supervisor assignments
- Workspace invitations, members
- Tenant settings
- **Level 2: Core Entities**
- Agents
- Workspaces
- **Level 3: Tenant Records**
- Tenants (tenant records themselves)
- **Redis Cleanup**
- All tenant-specific keys cleared
**Safety Features:**
โ Uses environment variables (no hardcoded IDs)
โ Creates backup before deletion
โ Respects foreign key constraints
โ Batch commits (every 10 tenants)
โ Detailed logging
โ Verification after completion
**Estimated Runtime:** 15-30 minutes
---
๐ก๏ธ PREVENTION STRATEGY
Step 3: Deploy Prevention Service
**New File:** backend-saas/core/test_data_prevention_service.py
**Features:**
- Blocks tenant creation with test keywords (test, demo, sample)
- Blocks suspicious email domains (test.com, example.com)
- Detects bulk creation patterns (3+ tenants/hour from same email)
- Logs all blocked requests for monitoring
- Environment-aware (only enforces in production)
**Integration Example:**
from core.test_data_prevention_service import TestDataPreventionService, get_test_data_prevention_service
@router.post("/tenants")
async def create_tenant(
request: Request,
tenant_data: TenantCreate,
prevention: TestDataPreventionService = Depends(get_test_data_prevention_service)
):
# Check for test data patterns
is_suspicious, reason = prevention.check_tenant_creation(
name=tenant_data.name,
subdomain=tenant_data.subdomain,
email=tenant_data.email
)
if is_suspicious:
# Log the attempt
prevention.log_suspicious_request(
endpoint="/tenants",
data=tenant_data.dict(),
reason=reason,
ip_address=request.client.host
)
# Block the request
raise HTTPException(
status_code=400,
detail=f"Suspicious request detected: {reason}"
)
# Proceed with normal tenant creation
...**Database Migration:**
# Apply migration for prevention logs table
cd backend-saas
alembic upgrade head**Migration:** 20260409_141941_8b8ea176d100.py
- Creates
test_data_prevention_logstable - Tracks all blocked test data attempts
- Useful for monitoring and analysis
---
๐ DIAGNOSTIC TOOLS
Script 1: Production Diagnostic
**Location:** backend-saas/scripts/diagnostic_prevent_test_data.py
**Checks:**
- Test tenant flag (
test_tenant=true) - Suspicious name patterns
- Suspicious email addresses
- Bulk creation patterns
- Inactive/abandoned tenants
- API abuse patterns
- Data quality issues
**Usage:**
export DATABASE_URL="postgresql://user:pass@host/db"
python3 backend-saas/scripts/diagnostic_prevent_test_data.pyScript 2: Quick Tenant Count
**Quick check of database state:**
-- Total tenants
SELECT COUNT(*) FROM tenants;
-- Test tenants
SELECT COUNT(*) FROM tenants WHERE test_tenant = true;
-- Suspicious names
SELECT COUNT(*) FROM tenants
WHERE LOWER(name) LIKE ANY('%test%', '%demo%', '%sample%');
-- Empty tenants (no agents)
SELECT COUNT(*) FROM tenants t
LEFT JOIN agents a ON a.tenant_id = t.id
WHERE a.id IS NULL;Script 3: Verify Brennan Tenant
-- Should return 1
SELECT COUNT(*) FROM tenants WHERE id = '31c06fc4-db22-4740-83ea-48ac14f25810';
-- Should show Brennan Machinery
SELECT name, subdomain, created_at FROM tenants
WHERE id = '31c06fc4-db22-4740-83ea-48ac14f25810';---
โ SAFETY CHECKS
Pre-Cleanup Checklist
- [ ] Backup solution is available
- [ ] Database admin is aware
- [ ] You have authorization to proceed
- [ ] This is production but all test data
- [ ] No real customers will be affected
- [ ] You understand this is PERMANENT deletion
- [ ]
DATABASE_URLenvironment variable is set correctly - [ ]
REDIS_URLenvironment variable is set correctly - [ ]
KEEP_TENANT_IDenvironment variable is set to Brennan's ID - [ ]
CONFIRM_CLEANUPenvironment variable is set to confirmation phrase
Post-Cleanup Verification
-- Should return 1
SELECT COUNT(*) FROM tenants;
-- Should return Brennan Machinery
SELECT name FROM tenants;
-- Should return Brennan's ID
SELECT id FROM tenants WHERE subdomain = 'brennan';
-- Should return 0 (no test tenants)
SELECT COUNT(*) FROM tenants WHERE test_tenant = true;Rollback Procedure
If something goes wrong:
- **Stop the script immediately**
- **Restore from backup**
- Backup location:
/tmp/brennan_tenant_backup_*.sql - Use database admin tools for restore
- **Contact database admin**
- For point-in-time recovery
- NeonDB supports PITR
---
๐ EXPECTED RESULTS
Before Cleanup
- Tenants: 1,829
- Agents: 3,658-18,290
- Test tenants: ~1,800+
- Redis keys: Thousands
After Cleanup
- Tenants: 1 (Brennan Machinery only)
- Agents: (Brennan's agents only)
- Test tenants: 0
- Redis keys: (Brennan's keys only)
---
๐ NEXT STEPS
- **Run diagnostic** to confirm test data extent
- **Review cleanup guide** at
backend-saas/scripts/CLEANUP_GUIDE.md - **Execute cleanup script** with proper environment variables
- **Verify results** with post-cleanup SQL queries
- **Deploy prevention service** to block future test data
- **Monitor logs** for any blocked test data attempts
---
๐ SUPPORT
If you encounter issues:
- Check script output for error messages
- Review backup file location
- Verify database connectivity
- Check Redis connection
- Review foreign key constraints if deletion fails
**Script Locations:**
- Cleanup:
backend-saas/scripts/cleanup_all_tenants_except_brennan.py - Diagnostic:
backend-saas/scripts/diagnostic_prevent_test_data.py - Prevention Service:
backend-saas/core/test_data_prevention_service.py - Guide:
backend-saas/scripts/CLEANUP_GUIDE.md
---
โ ๏ธ CRITICAL REMINDERS
- **This operation is irreversible** - Proceed with caution
- **Always use environment variables** - Never hardcode tenant IDs
- **Test in development first** - Before running in production
- **Have backup ready** - In case something goes wrong
- **Monitor the process** - Don't leave it unattended
- **Verify after completion** - Ensure only Brennan tenant remains
---
**Generated:** 2026-04-09
**Status:** Ready for execution
**Priority:** CRITICAL