""" Demo seed script — creates a polished demo account (alex@bankbot.dev) with realistic financial data: transactions, goals, investments, subscriptions, notifications, and a fraud alert. Run: python app/scripts/seed_demo.py """ import os import sys import uuid import random from datetime import datetime, timedelta sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) import bcrypt as _bcrypt from app.database.database import SessionLocal, engine from app.database.models import ( Base, User, Account, Transaction, Subscription, Goal, Investment, Notification, FraudLog ) Base.metadata.create_all(bind=engine) DEMO_EMAIL = "alex@bankbot.dev" DEMO_PASSWORD = "BankBot2026!" DEMO_NAME = "Alex Doe" def hash_pw(pw: str) -> str: return _bcrypt.hashpw(pw.encode(), _bcrypt.gensalt(rounds=12)).decode() def uid() -> str: return str(uuid.uuid4()) def seed(): db = SessionLocal() try: # ── Remove existing demo user ──────────────────────────────────────── existing = db.query(User).filter(User.email == DEMO_EMAIL).first() if existing: db.delete(existing) db.commit() print(f"Removed existing demo user: {DEMO_EMAIL}") # ── Create demo user ───────────────────────────────────────────────── user = User( id=uid(), email=DEMO_EMAIL, password_hash=hash_pw(DEMO_PASSWORD), profile_data={ "name": DEMO_NAME, "phone": "+1 (555) 012-3456", "avatar": "AD", "member_since": "2023-01-15", "plan": "Premium", }, financial_personality="Balanced Investor", ai_personalization_settings={ "risk_tolerance": "moderate", "investment_horizon": "long_term", "notifications": "all", "ai_tone": "analytical", }, ) db.add(user) db.flush() print(f"Created demo user: {DEMO_EMAIL}") # ── Accounts ───────────────────────────────────────────────────────── checking = Account(id=uid(), user_id=user.id, type="checking", balance=12_847.32, currency="USD", status="active") savings = Account(id=uid(), user_id=user.id, type="savings", balance=28_450.00, currency="USD", status="active") invest = Account(id=uid(), user_id=user.id, type="investment", balance=18_340.50, currency="USD", status="active") db.add_all([checking, savings, invest]) db.flush() print("Created 3 accounts (checking $12,847 | savings $28,450 | investment $18,340)") # ── Transactions — 6 months of realistic data ───────────────────────── now = datetime.utcnow() merchants = [ # (name, category, type, amount_range) ("Salary Deposit", "Income", "credit", (4800, 5200)), ("Freelance Payment", "Income", "credit", (800, 2000)), ("Whole Foods", "Groceries", "debit", (45, 180)), ("Trader Joe's", "Groceries", "debit", (30, 120)), ("Netflix", "Entertainment", "debit", (15, 16)), ("Spotify", "Entertainment", "debit", (9, 10)), ("Amazon", "Shopping", "debit", (25, 250)), ("Apple Store", "Tech", "debit", (10, 200)), ("Uber", "Transport", "debit", (8, 45)), ("Shell Gas", "Transport", "debit", (40, 80)), ("Starbucks", "Food", "debit", (5, 18)), ("Chipotle", "Food", "debit", (10, 25)), ("Planet Fitness", "Health", "debit", (24, 25)), ("CVS Pharmacy", "Health", "debit", (12, 60)), ("Con Edison", "Utilities", "debit", (80, 140)), ("Verizon", "Utilities", "debit", (85, 90)), ("Rent Payment", "Housing", "debit", (1950, 1950)), ("Dividend Income", "Investment", "credit", (120, 350)), ("Restaurant", "Food", "debit", (30, 90)), ("Target", "Shopping", "debit", (40, 150)), ] txns = [] for month_offset in range(6): month_start = (now.replace(day=1) - timedelta(days=month_offset * 30)) # Salary on 1st txns.append(Transaction( id=uid(), account_id=checking.id, amount=random.uniform(4800, 5200), type="credit", category="Income", merchant="Salary Deposit", timestamp=month_start + timedelta(hours=9), tags=["recurring", "income"], )) # Rent on 3rd txns.append(Transaction( id=uid(), account_id=checking.id, amount=1950.00, type="debit", category="Housing", merchant="Rent Payment", timestamp=month_start + timedelta(days=2, hours=10), tags=["recurring", "housing"], )) # Random daily transactions for _ in range(random.randint(18, 28)): m = random.choice(merchants[2:]) # skip salary/rent days_offset = random.randint(0, 28) hours_offset = random.randint(7, 22) txns.append(Transaction( id=uid(), account_id=checking.id, amount=round(random.uniform(*m[3]), 2), type=m[2], category=m[1], merchant=m[0], timestamp=month_start + timedelta(days=days_offset, hours=hours_offset), tags=[m[1].lower()], )) # One suspicious transaction for fraud demo fraud_txn = Transaction( id=uid(), account_id=checking.id, amount=847.00, type="debit", category="Shopping", merchant="Tech Store NYC", timestamp=now - timedelta(hours=2), tags=["flagged"], spending_emotion_label="impulsive", ) txns.append(fraud_txn) db.add_all(txns) db.flush() print(f"Created {len(txns)} transactions across 6 months") # ── Fraud log for the suspicious transaction ────────────────────────── fraud_log = FraudLog( id=uid(), transaction_id=fraud_txn.id, risk_score=0.78, suspicious_activity_details=( "Transaction amount ($847.00) is 3.2x above historical average. " "Location anomaly: merchant in NYC, usual activity in Brooklyn. " "Placed at 11:47 PM — outside normal spending hours." ), status="pending", ) db.add(fraud_log) print("Created fraud alert for demo transaction") # ── Goals ───────────────────────────────────────────────────────────── goals = [ Goal(id=uid(), user_id=user.id, title="Emergency Fund", target_amount=18_000, current_amount=14_200, target_date=now + timedelta(days=90), ai_generated_plan={"monthly_contribution": 1267, "months_remaining": 3}), Goal(id=uid(), user_id=user.id, title="Europe Vacation", target_amount=5_000, current_amount=2_800, target_date=now + timedelta(days=180), ai_generated_plan={"monthly_contribution": 367, "months_remaining": 6}), Goal(id=uid(), user_id=user.id, title="MacBook Pro", target_amount=2_500, current_amount=1_900, target_date=now + timedelta(days=45), ai_generated_plan={"monthly_contribution": 300, "months_remaining": 2}), Goal(id=uid(), user_id=user.id, title="Down Payment Fund", target_amount=80_000, current_amount=28_450, target_date=now + timedelta(days=730), ai_generated_plan={"monthly_contribution": 2148, "months_remaining": 24}), ] db.add_all(goals) print(f"Created {len(goals)} financial goals") # ── Investments ─────────────────────────────────────────────────────── investments = [ Investment(id=uid(), user_id=user.id, asset_name="S&P 500 Index Fund", type="mutual_fund", amount_invested=8_000, current_value=9_840, portfolio_allocation=53.6, ai_risk_analysis={"risk": "moderate", "expected_return": "8-10%", "recommendation": "hold"}), Investment(id=uid(), user_id=user.id, asset_name="Apple Inc (AAPL)", type="stock", amount_invested=3_000, current_value=3_720, portfolio_allocation=20.3, ai_risk_analysis={"risk": "moderate-high", "expected_return": "12-15%", "recommendation": "hold"}), Investment(id=uid(), user_id=user.id, asset_name="Bitcoin (BTC)", type="crypto", amount_invested=2_500, current_value=2_980, portfolio_allocation=16.2, ai_risk_analysis={"risk": "high", "expected_return": "variable", "recommendation": "reduce_exposure"}), Investment(id=uid(), user_id=user.id, asset_name="US Treasury Bonds", type="bond", amount_invested=1_800, current_value=1_800, portfolio_allocation=9.8, ai_risk_analysis={"risk": "low", "expected_return": "4.5%", "recommendation": "hold"}), ] db.add_all(investments) print(f"Created {len(investments)} investments (total value: ${sum(i.current_value for i in investments):,.0f})") # ── Subscriptions ───────────────────────────────────────────────────── subscriptions = [ Subscription(id=uid(), user_id=user.id, merchant="Netflix", amount=15.99, billing_cycle="monthly", active=True, ai_usage_detection={"last_used": "2 days ago", "usage_frequency": "high"}), Subscription(id=uid(), user_id=user.id, merchant="Spotify", amount=9.99, billing_cycle="monthly", active=True, ai_usage_detection={"last_used": "today", "usage_frequency": "daily"}), Subscription(id=uid(), user_id=user.id, merchant="Adobe Creative Cloud", amount=54.99, billing_cycle="monthly", active=True, ai_usage_detection={"last_used": "45 days ago", "usage_frequency": "low"}), Subscription(id=uid(), user_id=user.id, merchant="Planet Fitness", amount=24.99, billing_cycle="monthly", active=True, ai_usage_detection={"last_used": "1 week ago", "usage_frequency": "medium"}), Subscription(id=uid(), user_id=user.id, merchant="iCloud Storage", amount=2.99, billing_cycle="monthly", active=True, ai_usage_detection={"last_used": "today", "usage_frequency": "daily"}), Subscription(id=uid(), user_id=user.id, merchant="LinkedIn Premium", amount=39.99, billing_cycle="monthly", active=True, ai_usage_detection={"last_used": "60 days ago", "usage_frequency": "very_low"}), ] db.add_all(subscriptions) monthly_sub_cost = sum(s.amount for s in subscriptions) print(f"Created {len(subscriptions)} subscriptions (${monthly_sub_cost:.2f}/month)") # ── Notifications ───────────────────────────────────────────────────── notifications = [ Notification(id=uid(), user_id=user.id, title="🚨 Unusual Transaction Detected", message="A charge of $847.00 at 'Tech Store NYC' was flagged. " "This is 3.2x your average transaction and occurred at 11:47 PM. " "Please review and confirm.", type="alert", read_status=False, created_at=now - timedelta(hours=2)), Notification(id=uid(), user_id=user.id, title="💡 AI Weekly Insight", message="Your savings rate this month is 38.4% — 18% above the national average. " "At this pace, you'll reach your Emergency Fund goal in 3 months.", type="insight", read_status=False, created_at=now - timedelta(hours=6)), Notification(id=uid(), user_id=user.id, title="⚠️ Budget Alert: Shopping", message="You've spent $847 in Shopping this month — 141% of your $600 budget. " "Consider pausing non-essential purchases for the rest of the month.", type="warning", read_status=False, created_at=now - timedelta(hours=8)), Notification(id=uid(), user_id=user.id, title="🎯 Goal Milestone Reached", message="Your Emergency Fund is now 78.9% funded ($14,200 of $18,000). " "You're on track to complete it by August 2026.", type="insight", read_status=True, created_at=now - timedelta(days=1)), Notification(id=uid(), user_id=user.id, title="📊 Monthly Report Ready", message="Your May 2026 financial report is ready. " "Net savings: $1,847. Top category: Housing (38%). " "Health score improved by 3 points to 82/100.", type="insight", read_status=True, created_at=now - timedelta(days=2)), Notification(id=uid(), user_id=user.id, title="💰 Subscription Optimization", message="AI detected 2 underused subscriptions: Adobe CC ($54.99/mo, last used 45 days ago) " "and LinkedIn Premium ($39.99/mo, last used 60 days ago). " "Cancelling both saves $1,139.76/year.", type="warning", read_status=True, created_at=now - timedelta(days=3)), ] db.add_all(notifications) print(f"Created {len(notifications)} notifications ({sum(1 for n in notifications if not n.read_status)} unread)") db.commit() print("\n" + "="*60) print("DEMO ACCOUNT SEEDED SUCCESSFULLY") print("="*60) print(f" Email: {DEMO_EMAIL}") print(f" Password: {DEMO_PASSWORD}") print(f" Balance: ${checking.balance + savings.balance + invest.balance:,.2f} total") print(f" Score: 82/100 (estimated)") print(f" Fraud: 1 pending alert") print("="*60) except Exception as e: db.rollback() print(f"SEED FAILED: {e}") raise finally: db.close() if __name__ == "__main__": seed()