/** * LedgerOne Demo Account Seed Script * Creates a fully-populated demo account for testing all features. * * Usage: node seed-demo.mjs * Creds: demo@ledgerone.app / Demo1234! */ import { PrismaClient } from "@prisma/client"; import * as crypto from "crypto"; const prisma = new PrismaClient(); const DEMO_EMAIL = "demo@ledgerone.app"; const DEMO_PASSWORD = "Demo1234!"; function hashPassword(password) { const salt = crypto.randomBytes(16).toString("hex"); const hash = crypto.pbkdf2Sync(password, salt, 100_000, 64, "sha512").toString("hex"); return `${salt}:${hash}`; } function daysAgo(n) { const d = new Date(); d.setHours(12, 0, 0, 0); d.setDate(d.getDate() - n); return d; } async function main() { console.log("๐Ÿงน Cleaning up existing demo account..."); const existing = await prisma.user.findUnique({ where: { email: DEMO_EMAIL } }); if (existing) { const uid = existing.id; // Delete leaf models first, then parents await prisma.auditLog.deleteMany({ where: { userId: uid } }); await prisma.refreshToken.deleteMany({ where: { userId: uid } }); await prisma.emailVerificationToken.deleteMany({ where: { userId: uid } }); await prisma.passwordResetToken.deleteMany({ where: { userId: uid } }); await prisma.subscription.deleteMany({ where: { userId: uid } }); await prisma.exportLog.deleteMany({ where: { userId: uid } }); await prisma.googleConnection.deleteMany({ where: { userId: uid } }); const taxReturns = await prisma.taxReturn.findMany({ where: { userId: uid } }); for (const tr of taxReturns) { await prisma.taxDocument.deleteMany({ where: { taxReturnId: tr.id } }); } await prisma.taxReturn.deleteMany({ where: { userId: uid } }); const accounts = await prisma.account.findMany({ where: { userId: uid } }); for (const account of accounts) { const txRaws = await prisma.transactionRaw.findMany({ where: { accountId: account.id } }); for (const tx of txRaws) { await prisma.ruleExecution.deleteMany({ where: { transactionId: tx.id } }); await prisma.transactionDerived.deleteMany({ where: { rawTransactionId: tx.id } }); } await prisma.transactionRaw.deleteMany({ where: { accountId: account.id } }); } await prisma.account.deleteMany({ where: { userId: uid } }); const rules = await prisma.rule.findMany({ where: { userId: uid } }); for (const rule of rules) { await prisma.ruleExecution.deleteMany({ where: { ruleId: rule.id } }); } await prisma.rule.deleteMany({ where: { userId: uid } }); await prisma.user.delete({ where: { id: uid } }); console.log(" โœ“ Removed previous demo account"); } // โ”€โ”€ User โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ console.log("\n๐Ÿ‘ค Creating demo user..."); const user = await prisma.user.create({ data: { email: DEMO_EMAIL, passwordHash: hashPassword(DEMO_PASSWORD), fullName: "Alex Chen", emailVerified: true, // skip email verification step companyName: "LedgerOne Demo Corp", city: "San Francisco", state: "CA", country: "US", }, }); console.log(` โœ“ ${user.email} (id: ${user.id})`); // โ”€โ”€ Subscription โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ await prisma.subscription.create({ data: { userId: user.id, plan: "pro", currentPeriodEnd: new Date(Date.now() + 30 * 86_400_000), cancelAtPeriodEnd: false, }, }); console.log(" โœ“ Pro subscription"); // โ”€โ”€ Accounts โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ console.log("\n๐Ÿฆ Creating accounts..."); const checking = await prisma.account.create({ data: { userId: user.id, institutionName: "Chase Bank", accountType: "checking", mask: "4521", currentBalance: 12847.53, availableBalance: 12347.53, isoCurrencyCode: "USD", isActive: true, }, }); const credit = await prisma.account.create({ data: { userId: user.id, institutionName: "American Express", accountType: "credit", mask: "2834", currentBalance: -2341.88, // negative = you owe this availableBalance: 7658.12, isoCurrencyCode: "USD", isActive: true, }, }); const savings = await prisma.account.create({ data: { userId: user.id, institutionName: "Ally Bank", accountType: "savings", mask: "9012", currentBalance: 28500.00, availableBalance: 28500.00, isoCurrencyCode: "USD", isActive: true, }, }); console.log(" โœ“ Chase Checking *4521"); console.log(" โœ“ Amex Credit *2834"); console.log(" โœ“ Ally Savings *9012"); // โ”€โ”€ Transactions โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // Convention: positive = money leaving (expense), negative = money entering (income/deposit) const txDataset = [ // โ”€โ”€ INCOME (checking) โ”€โ”€ { acct: checking, d: 2, amt: -5800.00, desc: "PAYROLL DIRECT DEPOSIT - ACME CORP", cat: "Income" }, { acct: checking, d: 32, amt: -5800.00, desc: "PAYROLL DIRECT DEPOSIT - ACME CORP", cat: "Income" }, { acct: checking, d: 62, amt: -5800.00, desc: "PAYROLL DIRECT DEPOSIT - ACME CORP", cat: "Income" }, { acct: checking, d: 92, amt: -5800.00, desc: "PAYROLL DIRECT DEPOSIT - ACME CORP", cat: "Income" }, { acct: checking, d: 122, amt: -5800.00, desc: "PAYROLL DIRECT DEPOSIT - ACME CORP", cat: "Income" }, { acct: checking, d: 152, amt: -5800.00, desc: "PAYROLL DIRECT DEPOSIT - ACME CORP", cat: "Income" }, { acct: savings, d: 5, amt: -200.00, desc: "INTEREST EARNED - ALLY BANK", cat: "Income" }, { acct: savings, d: 35, amt: -194.50, desc: "INTEREST EARNED - ALLY BANK", cat: "Income" }, { acct: savings, d: 65, amt: -201.20, desc: "INTEREST EARNED - ALLY BANK", cat: "Income" }, // โ”€โ”€ RENT (checking) โ”€โ”€ { acct: checking, d: 5, amt: 2200.00, desc: "ACH - RENT - HARBOR VIEW APARTMENTS", cat: "Rent & Mortgage" }, { acct: checking, d: 35, amt: 2200.00, desc: "ACH - RENT - HARBOR VIEW APARTMENTS", cat: "Rent & Mortgage" }, { acct: checking, d: 65, amt: 2200.00, desc: "ACH - RENT - HARBOR VIEW APARTMENTS", cat: "Rent & Mortgage" }, { acct: checking, d: 95, amt: 2200.00, desc: "ACH - RENT - HARBOR VIEW APARTMENTS", cat: "Rent & Mortgage" }, { acct: checking, d: 125, amt: 2200.00, desc: "ACH - RENT - HARBOR VIEW APARTMENTS", cat: "Rent & Mortgage" }, { acct: checking, d: 155, amt: 2200.00, desc: "ACH - RENT - HARBOR VIEW APARTMENTS", cat: "Rent & Mortgage" }, // โ”€โ”€ UTILITIES (checking) โ”€โ”€ { acct: checking, d: 8, amt: 94.50, desc: "PG&E ELECTRIC BILL PAYMENT", cat: "Utilities" }, { acct: checking, d: 38, amt: 87.20, desc: "PG&E ELECTRIC BILL PAYMENT", cat: "Utilities" }, { acct: checking, d: 68, amt: 112.80, desc: "PG&E ELECTRIC BILL PAYMENT", cat: "Utilities" }, { acct: checking, d: 98, amt: 103.40, desc: "PG&E ELECTRIC BILL PAYMENT", cat: "Utilities" }, { acct: checking, d: 10, amt: 65.00, desc: "COMCAST XFINITY INTERNET", cat: "Utilities" }, { acct: checking, d: 40, amt: 65.00, desc: "COMCAST XFINITY INTERNET", cat: "Utilities" }, { acct: checking, d: 70, amt: 65.00, desc: "COMCAST XFINITY INTERNET", cat: "Utilities" }, { acct: checking, d: 100, amt: 65.00, desc: "COMCAST XFINITY INTERNET", cat: "Utilities" }, // โ”€โ”€ GROCERIES (checking) โ”€โ”€ { acct: checking, d: 3, amt: 127.43, desc: "WHOLE FOODS MARKET #1234 SAN FRANCISCO", cat: "Groceries" }, { acct: checking, d: 11, amt: 89.22, desc: "TRADER JOE S #456 SF", cat: "Groceries" }, { acct: checking, d: 18, amt: 145.67, desc: "WHOLE FOODS MARKET #1234 SAN FRANCISCO", cat: "Groceries" }, { acct: checking, d: 25, amt: 73.11, desc: "SAFEWAY #789", cat: "Groceries" }, { acct: checking, d: 33, amt: 118.54, desc: "WHOLE FOODS MARKET #1234 SAN FRANCISCO", cat: "Groceries" }, { acct: checking, d: 45, amt: 92.30, desc: "TRADER JOE S #456 SF", cat: "Groceries" }, { acct: checking, d: 55, amt: 131.20, desc: "WHOLE FOODS MARKET #1234 SAN FRANCISCO", cat: "Groceries" }, { acct: checking, d: 70, amt: 85.75, desc: "SAFEWAY #789", cat: "Groceries" }, { acct: checking, d: 82, amt: 104.88, desc: "WHOLE FOODS MARKET #1234 SAN FRANCISCO", cat: "Groceries" }, { acct: checking, d: 105, amt: 76.42, desc: "TRADER JOE S #456 SF", cat: "Groceries" }, // โ”€โ”€ HEALTHCARE (checking) โ”€โ”€ { acct: checking, d: 15, amt: 30.00, desc: "CVS PHARMACY #1122", cat: "Healthcare" }, { acct: checking, d: 60, amt: 250.00, desc: "KAISER PERMANENTE COPAY", cat: "Healthcare" }, { acct: checking, d: 110, amt: 45.00, desc: "CVS PHARMACY #1122", cat: "Healthcare" }, { acct: checking, d: 140, amt: 180.00, desc: "UCSF MEDICAL CENTER", cat: "Healthcare" }, // โ”€โ”€ DINING (credit) โ”€โ”€ { acct: credit, d: 1, amt: 68.40, desc: "NOBU RESTAURANT SF", cat: "Dining & Restaurants" }, { acct: credit, d: 4, amt: 14.50, desc: "STARBUCKS #3421 SAN FRANCISCO CA", cat: "Dining & Restaurants" }, { acct: credit, d: 7, amt: 42.80, desc: "CHIPOTLE MEXICAN GRILL", cat: "Dining & Restaurants" }, { acct: credit, d: 13, amt: 89.20, desc: "MOURAD RESTAURANT SF", cat: "Dining & Restaurants" }, { acct: credit, d: 16, amt: 23.60, desc: "SWEETGREEN #55 SF", cat: "Dining & Restaurants" }, { acct: credit, d: 22, amt: 112.50, desc: "BENU RESTAURANT SAN FRANCISCO", cat: "Dining & Restaurants" }, { acct: credit, d: 29, amt: 18.90, desc: "STARBUCKS #3421 SAN FRANCISCO CA", cat: "Dining & Restaurants" }, { acct: credit, d: 36, amt: 55.30, desc: "IN-N-OUT BURGER #77", cat: "Dining & Restaurants" }, { acct: credit, d: 48, amt: 78.10, desc: "NOBU RESTAURANT SF", cat: "Dining & Restaurants" }, { acct: credit, d: 75, amt: 32.40, desc: "CHIPOTLE MEXICAN GRILL", cat: "Dining & Restaurants" }, { acct: credit, d: 90, amt: 44.20, desc: "THE FRENCH LAUNDRY YOUNTVILLE", cat: "Dining & Restaurants" }, // โ”€โ”€ SUBSCRIPTIONS (credit) โ”€โ”€ { acct: credit, d: 9, amt: 15.99, desc: "NETFLIX.COM SUBSCRIPTION", cat: "Subscriptions" }, { acct: credit, d: 9, amt: 9.99, desc: "SPOTIFY PREMIUM", cat: "Subscriptions" }, { acct: credit, d: 9, amt: 14.99, desc: "OPENAI CHATGPT PLUS", cat: "Subscriptions" }, { acct: credit, d: 9, amt: 19.99, desc: "GITHUB COPILOT SUBSCRIPTION", cat: "Subscriptions" }, { acct: credit, d: 39, amt: 15.99, desc: "NETFLIX.COM SUBSCRIPTION", cat: "Subscriptions" }, { acct: credit, d: 39, amt: 9.99, desc: "SPOTIFY PREMIUM", cat: "Subscriptions" }, { acct: credit, d: 39, amt: 14.99, desc: "OPENAI CHATGPT PLUS", cat: "Subscriptions" }, { acct: credit, d: 39, amt: 19.99, desc: "GITHUB COPILOT SUBSCRIPTION", cat: "Subscriptions" }, { acct: credit, d: 69, amt: 15.99, desc: "NETFLIX.COM SUBSCRIPTION", cat: "Subscriptions" }, { acct: credit, d: 69, amt: 9.99, desc: "SPOTIFY PREMIUM", cat: "Subscriptions" }, // โ”€โ”€ ENTERTAINMENT (credit) โ”€โ”€ { acct: credit, d: 20, amt: 24.99, desc: "AMC THEATRES TICKET SAN FRANCISCO", cat: "Entertainment" }, { acct: credit, d: 85, amt: 189.00, desc: "GOLDEN STATE WARRIORS - CHASE CENTER", cat: "Entertainment" }, { acct: credit, d: 130, amt: 95.00, desc: "TICKETMASTER CONCERT TICKETS", cat: "Entertainment" }, // โ”€โ”€ TRANSPORTATION (credit) โ”€โ”€ { acct: credit, d: 2, amt: 18.40, desc: "UBER TRIP SAN FRANCISCO CA", cat: "Transportation" }, { acct: credit, d: 6, amt: 22.10, desc: "UBER TRIP SAN FRANCISCO CA", cat: "Transportation" }, { acct: credit, d: 13, amt: 15.80, desc: "LYFT RIDE SAN FRANCISCO", cat: "Transportation" }, { acct: credit, d: 27, amt: 89.00, desc: "SHELL OIL GAS STATION #4421", cat: "Transportation" }, { acct: credit, d: 48, amt: 76.50, desc: "SHELL OIL GAS STATION #4421", cat: "Transportation" }, { acct: credit, d: 58, amt: 21.60, desc: "UBER TRIP SAN FRANCISCO CA", cat: "Transportation" }, { acct: credit, d: 72, amt: 88.00, desc: "BART CLIPPER CARD RELOAD", cat: "Transportation" }, // โ”€โ”€ SHOPPING (credit) โ”€โ”€ { acct: credit, d: 14, amt: 243.50, desc: "AMAZON.COM PURCHASE", cat: "Shopping" }, { acct: credit, d: 30, amt: 89.99, desc: "AMAZON.COM PURCHASE", cat: "Shopping" }, { acct: credit, d: 53, amt: 1450.00, desc: "APPLE.COM/BILL - IPAD PRO", cat: "Shopping" }, { acct: credit, d: 66, amt: 178.00, desc: "NORDSTROM #0234 SF", cat: "Shopping" }, { acct: credit, d: 90, amt: 340.00, desc: "BEST BUY #1234 DALY CITY", cat: "Shopping" }, { acct: credit, d: 115, amt: 67.50, desc: "AMAZON.COM PURCHASE", cat: "Shopping" }, // โ”€โ”€ CREDIT CARD PAYMENTS (checking) โ”€โ”€ { acct: checking, d: 20, amt: 1800.00, desc: "AMEX AUTOPAY - CREDIT CARD PAYMENT", cat: "Transfer" }, { acct: checking, d: 50, amt: 2100.00, desc: "AMEX AUTOPAY - CREDIT CARD PAYMENT", cat: "Transfer" }, { acct: checking, d: 80, amt: 1650.00, desc: "AMEX AUTOPAY - CREDIT CARD PAYMENT", cat: "Transfer" }, { acct: checking, d: 110, amt: 1950.00, desc: "AMEX AUTOPAY - CREDIT CARD PAYMENT", cat: "Transfer" }, // โ”€โ”€ SAVINGS TRANSFERS (checking โ†’ savings) โ”€โ”€ { acct: checking, d: 3, amt: 500.00, desc: "TRANSFER TO ALLY SAVINGS *9012", cat: "Transfer" }, { acct: checking, d: 33, amt: 500.00, desc: "TRANSFER TO ALLY SAVINGS *9012", cat: "Transfer" }, { acct: checking, d: 63, amt: 500.00, desc: "TRANSFER TO ALLY SAVINGS *9012", cat: "Transfer" }, ]; console.log("\n๐Ÿ’ณ Creating transactions..."); let txCount = 0; for (const [i, tx] of txDataset.entries()) { const raw = await prisma.transactionRaw.create({ data: { accountId: tx.acct.id, bankTransactionId: `demo-${user.id.slice(0, 8)}-${String(i).padStart(3, "0")}`, date: daysAgo(tx.d), amount: tx.amt, description: tx.desc, source: "manual", rawPayload: { demo: true }, }, }); await prisma.transactionDerived.create({ data: { rawTransactionId: raw.id, userCategory: tx.cat, isHidden: false, modifiedBy: user.id, }, }); txCount++; } console.log(` โœ“ ${txCount} transactions created`); // โ”€โ”€ Categorization Rules โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ console.log("\n๐Ÿ“‹ Creating categorization rules..."); const rules = [ { name: "Whole Foods โ†’ Groceries", priority: 10, conditions: { operator: "AND", filters: [{ field: "description", op: "contains", value: "WHOLE FOODS" }] }, actions: [{ type: "setCategory", value: "Groceries" }], }, { name: "Trader Joe's โ†’ Groceries", priority: 10, conditions: { operator: "AND", filters: [{ field: "description", op: "contains", value: "TRADER JOE" }] }, actions: [{ type: "setCategory", value: "Groceries" }], }, { name: "Netflix โ†’ Subscriptions", priority: 10, conditions: { operator: "AND", filters: [{ field: "description", op: "contains", value: "NETFLIX" }] }, actions: [{ type: "setCategory", value: "Subscriptions" }], }, { name: "Uber/Lyft โ†’ Transportation", priority: 10, conditions: { operator: "OR", filters: [ { field: "description", op: "contains", value: "UBER" }, { field: "description", op: "contains", value: "LYFT" }, ]}, actions: [{ type: "setCategory", value: "Transportation" }], }, { name: "Amazon โ†’ Shopping", priority: 10, conditions: { operator: "AND", filters: [{ field: "description", op: "contains", value: "AMAZON" }] }, actions: [{ type: "setCategory", value: "Shopping" }], }, { name: "Payroll โ†’ Income", priority: 20, conditions: { operator: "AND", filters: [{ field: "description", op: "contains", value: "PAYROLL" }] }, actions: [{ type: "setCategory", value: "Income" }], }, { name: "Starbucks โ†’ Dining", priority: 10, conditions: { operator: "AND", filters: [{ field: "description", op: "contains", value: "STARBUCKS" }] }, actions: [{ type: "setCategory", value: "Dining & Restaurants" }], }, { name: "Large purchase note (>$500)", priority: 5, conditions: { operator: "AND", filters: [{ field: "amount", op: "gt", value: 500 }] }, actions: [{ type: "addNote", value: "Large purchase โ€” review for tax deduction" }], }, ]; for (const rule of rules) { await prisma.rule.create({ data: { userId: user.id, name: rule.name, priority: rule.priority, conditions: rule.conditions, actions: rule.actions, isActive: true, }, }); } console.log(` โœ“ ${rules.length} rules created`); // โ”€โ”€ Draft Tax Return โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ console.log("\n๐Ÿ“„ Creating draft tax return..."); await prisma.taxReturn.create({ data: { userId: user.id, taxYear: 2025, filingType: "individual", jurisdictions: ["federal", "CA"], status: "draft", summary: { totalIncome: 69600, totalExpenses: 42580, netIncome: 27020, categories: { "Income": 69600.00, "Rent & Mortgage": 13200.00, "Groceries": 1044.52, "Dining & Restaurants": 679.90, "Transportation": 411.40, "Subscriptions": 165.93, "Shopping": 2469.99, "Healthcare": 505.00, "Utilities": 755.90, "Entertainment": 308.99, "Transfer": 10500.00, }, }, }, }); console.log(" โœ“ Draft 2025 tax return"); // โ”€โ”€ Audit Log โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ await prisma.auditLog.create({ data: { userId: user.id, action: "auth.register", metadata: { email: DEMO_EMAIL, source: "seed-script" } }, }); // โ”€โ”€ Summary โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ console.log(` โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— โ•‘ Demo Account Ready โ•‘ โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ โ•‘ Email: demo@ledgerone.app โ•‘ โ•‘ Password: Demo1234! โ•‘ โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ โ•‘ Features populated: โ•‘ โ•‘ โœ“ Email verified (no confirmation needed) โ•‘ โ•‘ โœ“ Pro subscription (30-day period) โ•‘ โ•‘ โœ“ 3 accounts (checking/credit/savings) โ•‘ โ•‘ โœ“ ${String(txCount).padEnd(3)} transactions (6 months of data) โ•‘ โ•‘ โœ“ ${String(rules.length).padEnd(3)} categorization rules โ•‘ โ•‘ โœ“ Draft 2025 tax return โ•‘ โ•‘ โœ“ 2FA disabled (enable via Settings โ†’ 2FA) โ•‘ โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• `); } main() .catch((e) => { console.error("โŒ Seed failed:", e.message); process.exit(1); }) .finally(() => prisma.$disconnect());