.do
Use Cases

Fintech Platform

Build a complete financial services platform with Business-as-Code

Build a complete, autonomous financial services platform using Business-as-Code principles.

Overview

This use case demonstrates building a fintech platform that:

  • Manages customer accounts securely
  • Processes transactions in real-time
  • Handles KYC/AML compliance automatically
  • Detects fraud using AI
  • Processes payments through multiple channels
  • Manages reconciliation workflows
  • Generates regulatory reports
  • Provides financial insights and analytics

Architecture

graph TB subgraph Frontend["User Experience"] WebApp[Web Application] MobileApp[Mobile App] API[REST/GraphQL API] end subgraph Core["Core Banking"] Accounts[Account Management] Ledger[General Ledger] Transactions[Transaction Engine] Balance[Balance Management] end subgraph Processing["Payment Processing"] PaymentGateway[Payment Gateway] ACH[ACH Processing] Wire[Wire Transfers] Cards[Card Processing] end subgraph Compliance["Compliance & Risk"] KYC[KYC Verification] AML[AML Screening] Fraud[Fraud Detection] Risk[Risk Assessment] end subgraph AI["AI Services"] FraudAI[Fraud Detection AI] RiskAI[Risk Scoring AI] InsightsAI[Financial Insights] SupportAI[Customer Support AI] end subgraph Integration["External Systems"] Plaid[Plaid/Banking APIs] Stripe[Payment Providers] Identity[Identity Verification] Reporting[Regulatory Reporting] end WebApp --> API MobileApp --> API API --> Accounts Accounts --> Ledger Accounts --> Transactions Transactions --> Balance Transactions --> PaymentGateway PaymentGateway --> ACH PaymentGateway --> Wire PaymentGateway --> Cards Accounts --> KYC Transactions --> AML Transactions --> Fraud Accounts --> Risk Fraud -.->|AI| FraudAI Risk -.->|AI| RiskAI Accounts -.->|AI| InsightsAI KYC --> Identity PaymentGateway --> Stripe Accounts --> Plaid Compliance --> Reporting

Core Entities

Financial Accounts

import $, { db, on, send, ai } from 'sdk.do'

// Create bank account
const account = await $.BankAccount.create({
  $type: 'BankAccount',

  // Account details
  accountNumber: generateAccountNumber(),
  accountType: 'checking',
  bankAccountType: 'DepositAccount',

  // Ownership
  accountHolder: customer,

  // Balance
  accountBalance: {
    $type: 'MonetaryAmount',
    value: 0,
    currency: 'USD',
  },
  availableBalance: {
    $type: 'MonetaryAmount',
    value: 0,
    currency: 'USD',
  },

  // Limits
  dailyTransactionLimit: 5000,
  monthlyTransactionLimit: 50000,

  // Interest
  interestRate: 0.01,
  interestCompoundingFrequency: 'monthly',

  // Status
  accountStatus: 'active',
  openedDate: new Date(),

  // Metadata
  createdAt: new Date(),
})

await db.relate(customer, $.owns, account)

Transactions

// Financial transaction
const transaction = await $.FinancialTransaction.create({
  $type: 'FinancialTransaction',

  // Transaction details
  identifier: `TXN-${Date.now()}`,
  transactionType: 'Transfer',

  // Parties
  sender: fromAccount,
  recipient: toAccount,

  // Amount
  amount: {
    $type: 'MonetaryAmount',
    value: 100.0,
    currency: 'USD',
  },

  // Fees
  transactionFee: {
    $type: 'MonetaryAmount',
    value: 0.5,
    currency: 'USD',
  },

  // Status
  transactionStatus: 'pending',

  // Timestamps
  transactionDate: new Date(),
  settledDate: null,

  // Metadata
  description: 'Payment for invoice #12345',
  metadata: {
    invoiceId: '12345',
    category: 'business',
  },
})

Business Functions

1. Account Opening & KYC

Complete account opening with automated KYC/AML verification.

// Account opening workflow
async function openAccount(params: { customer: Person | Organization; accountType: 'checking' | 'savings' | 'business'; initialDeposit?: number }) {
  const { customer, accountType, initialDeposit } = params

  // Step 1: Verify identity (KYC)
  const kycResult = await verifyIdentity(customer)

  if (!kycResult.verified) {
    throw new Error(`KYC verification failed: ${kycResult.reason}`)
  }

  // Step 2: AML screening
  const amlResult = await screenAML(customer)

  if (amlResult.risk === 'high') {
    // Flag for manual review
    await send($.Review.required, {
      customer,
      reason: 'high-risk-aml',
      details: amlResult,
    })
    throw new Error('Account requires manual review')
  }

  // Step 3: Risk assessment
  const riskScore = await ai.analyze('customer-risk', {
    customer,
    kyc: kycResult,
    aml: amlResult,
    accountType,
  })

  // Step 4: Create account
  const account = await $.BankAccount.create({
    $type: 'BankAccount',
    accountNumber: generateAccountNumber(),
    routingNumber: getRoutingNumber(),
    accountType,
    accountHolder: customer,

    // Initial balance
    accountBalance: {
      $type: 'MonetaryAmount',
      value: initialDeposit || 0,
      currency: 'USD',
    },
    availableBalance: {
      $type: 'MonetaryAmount',
      value: initialDeposit || 0,
      currency: 'USD',
    },

    // Limits based on risk
    dailyTransactionLimit: riskScore.limits.daily,
    monthlyTransactionLimit: riskScore.limits.monthly,

    // Compliance
    kycVerified: true,
    kycVerifiedAt: new Date(),
    kycProvider: kycResult.provider,
    riskLevel: riskScore.level,

    // Status
    accountStatus: 'active',
    openedDate: new Date(),
  })

  await db.relate(customer, $.owns, account)

  // Step 5: Create general ledger entries
  if (initialDeposit > 0) {
    await createLedgerEntry({
      account: account.$id,
      type: 'credit',
      amount: initialDeposit,
      description: 'Initial deposit',
      category: 'deposit',
    })
  }

  // Step 6: Send welcome materials
  await send($.Email.send, {
    to: customer.email,
    template: 'account-opened',
    data: {
      account,
      accountNumber: account.accountNumber,
      routingNumber: account.routingNumber,
    },
  })

  // Step 7: Set up fraud monitoring
  await send($.Monitoring.enable, {
    account,
    rules: riskScore.monitoringRules,
  })

  await send($.Account.opened, account)

  return account
}

// KYC verification
async function verifyIdentity(customer: Person | Organization) {
  const isOrganization = customer.$type === 'Organization'

  if (isOrganization) {
    // Business verification
    return await verifyBusiness(customer as Organization)
  }

  // Individual verification
  const person = customer as Person

  // Call identity verification service
  const verification = await send($.Identity.verify, {
    firstName: person.givenName,
    lastName: person.familyName,
    dateOfBirth: person.birthDate,
    ssn: person.taxID,
    address: person.address,
    phone: person.telephone,
    email: person.email,

    // Document verification
    documents: [
      {
        type: 'government_id',
        number: person.identifier,
        expirationDate: person.identifierExpiration,
      },
    ],
  })

  // Save verification result
  await db.update($.Person, person.$id, {
    kycStatus: verification.status,
    kycVerifiedAt: verification.verified ? new Date() : null,
    kycProvider: 'veriff',
    kycReferenceId: verification.id,
  })

  return {
    verified: verification.status === 'approved',
    status: verification.status,
    reason: verification.reason,
    provider: 'veriff',
    timestamp: new Date(),
  }
}

// AML screening
async function screenAML(customer: Person | Organization) {
  // Check sanctions lists
  const sanctionsCheck = await send($.AML.checkSanctions, {
    name: customer.name,
    address: customer.address,
    dateOfBirth: customer.birthDate,
  })

  // Check PEP (Politically Exposed Person) lists
  const pepCheck = await send($.AML.checkPEP, {
    name: customer.name,
  })

  // Check adverse media
  const mediaCheck = await ai.analyze('adverse-media', {
    name: customer.name,
    sources: ['news', 'legal', 'regulatory'],
  })

  // Calculate risk score
  const riskScore = calculateAMLRisk({
    sanctions: sanctionsCheck,
    pep: pepCheck,
    media: mediaCheck,
  })

  // Save screening result
  await db.create($.AMLScreening, {
    customer: customer.$id,
    screenedAt: new Date(),
    sanctionsMatch: sanctionsCheck.matches.length > 0,
    pepMatch: pepCheck.matches.length > 0,
    adverseMedia: mediaCheck.findings.length > 0,
    riskScore: riskScore.score,
    riskLevel: riskScore.level,
    status: riskScore.level === 'high' ? 'flagged' : 'cleared',
  })

  return {
    risk: riskScore.level,
    score: riskScore.score,
    findings: {
      sanctions: sanctionsCheck.matches,
      pep: pepCheck.matches,
      media: mediaCheck.findings,
    },
  }
}

2. Transaction Processing

Real-time transaction processing with validation and authorization.

// Process transaction
async function processTransaction(params: { fromAccount: BankAccount; toAccount: BankAccount; amount: number; description?: string; metadata?: any }) {
  const { fromAccount, toAccount, amount, description, metadata } = params

  // Create transaction record
  const transaction = await $.FinancialTransaction.create({
    $type: 'FinancialTransaction',
    identifier: `TXN-${Date.now()}`,
    transactionType: 'Transfer',

    sender: fromAccount,
    recipient: toAccount,

    amount: {
      $type: 'MonetaryAmount',
      value: amount,
      currency: 'USD',
    },

    transactionStatus: 'pending',
    transactionDate: new Date(),

    description,
    metadata,
  })

  await send($.Transaction.created, transaction)

  return transaction
}

// Transaction validation
on($.Transaction.created, async (transaction) => {
  try {
    // Step 1: Validate accounts
    const fromAccount = transaction.sender
    const toAccount = transaction.recipient

    if (fromAccount.accountStatus !== 'active') {
      throw new Error('Sender account is not active')
    }

    if (toAccount.accountStatus !== 'active') {
      throw new Error('Recipient account is not active')
    }

    // Step 2: Check available balance
    const amount = transaction.amount.value
    const fee = calculateTransactionFee(transaction)
    const totalAmount = amount + fee

    if (fromAccount.availableBalance.value < totalAmount) {
      throw new Error('Insufficient funds')
    }

    // Step 3: Check transaction limits
    const dailyTotal = await getDailyTransactionTotal(fromAccount)

    if (dailyTotal + amount > fromAccount.dailyTransactionLimit) {
      throw new Error('Daily transaction limit exceeded')
    }

    // Step 4: Fraud detection
    const fraudCheck = await ai.analyze('fraud-detection', {
      transaction,
      account: fromAccount,
      history: await getTransactionHistory(fromAccount, '30d'),
      patterns: await getCustomerBehavior(fromAccount.accountHolder),
    })

    if (fraudCheck.risk === 'high' && fraudCheck.confidence > 0.8) {
      // Block transaction and alert
      await db.update($.FinancialTransaction, transaction.$id, {
        transactionStatus: 'blocked',
        blockReason: 'fraud-suspected',
      })

      await send($.Fraud.detected, {
        transaction,
        fraudCheck,
      })

      throw new Error('Transaction blocked: fraud suspected')
    }

    if (fraudCheck.risk === 'medium' && fraudCheck.confidence > 0.7) {
      // Require additional verification
      await db.update($.FinancialTransaction, transaction.$id, {
        transactionStatus: 'verification-required',
      })

      await send($.Transaction.requiresVerification, {
        transaction,
        reason: fraudCheck.reason,
      })

      return
    }

    // Step 5: Reserve funds
    await db.update($.BankAccount, fromAccount.$id, {
      'availableBalance.value': fromAccount.availableBalance.value - totalAmount,
    })

    // Step 6: Process transaction
    await send($.Transaction.process, transaction)
  } catch (error) {
    // Update transaction status
    await db.update($.FinancialTransaction, transaction.$id, {
      transactionStatus: 'failed',
      failureReason: error.message,
    })

    await send($.Transaction.failed, {
      transaction,
      error: error.message,
    })

    throw error
  }
})

// Execute transaction
on($.Transaction.process, async (transaction) => {
  const fromAccount = transaction.sender
  const toAccount = transaction.recipient
  const amount = transaction.amount.value
  const fee = calculateTransactionFee(transaction)

  // Create ledger entries
  const timestamp = new Date()

  // Debit from sender
  await createLedgerEntry({
    account: fromAccount.$id,
    transaction: transaction.$id,
    type: 'debit',
    amount: amount + fee,
    description: transaction.description,
    timestamp,
  })

  // Update sender balance
  await db.update($.BankAccount, fromAccount.$id, {
    'accountBalance.value': fromAccount.accountBalance.value - amount - fee,
  })

  // Credit to recipient
  await createLedgerEntry({
    account: toAccount.$id,
    transaction: transaction.$id,
    type: 'credit',
    amount,
    description: transaction.description,
    timestamp,
  })

  // Update recipient balance
  await db.update($.BankAccount, toAccount.$id, {
    'accountBalance.value': toAccount.accountBalance.value + amount,
    'availableBalance.value': toAccount.availableBalance.value + amount,
  })

  // Record fee revenue
  if (fee > 0) {
    await createLedgerEntry({
      account: 'revenue',
      transaction: transaction.$id,
      type: 'credit',
      amount: fee,
      description: 'Transaction fee',
      category: 'fee-income',
      timestamp,
    })
  }

  // Update transaction
  await db.update($.FinancialTransaction, transaction.$id, {
    transactionStatus: 'completed',
    settledDate: timestamp,
    transactionFee: {
      $type: 'MonetaryAmount',
      value: fee,
      currency: 'USD',
    },
  })

  await send($.Transaction.completed, transaction)

  // Send notifications
  await send($.Notification.send, {
    to: fromAccount.accountHolder,
    type: 'transaction',
    message: `Payment sent: $${amount.toFixed(2)}`,
    data: { transaction },
  })

  await send($.Notification.send, {
    to: toAccount.accountHolder,
    type: 'transaction',
    message: `Payment received: $${amount.toFixed(2)}`,
    data: { transaction },
  })
})

3. Fraud Detection

AI-powered real-time fraud detection and prevention.

// Fraud detection engine
async function detectFraud(transaction: FinancialTransaction) {
  const account = transaction.sender

  // Gather context
  const context = {
    transaction,
    account,

    // Transaction patterns
    history: await getTransactionHistory(account, '90d'),
    frequency: await getTransactionFrequency(account),
    typicalAmount: await getTypicalTransactionAmount(account),

    // Account patterns
    accountAge: differenceInDays(new Date(), account.openedDate),
    averageBalance: await getAverageBalance(account),

    // Behavioral patterns
    typicalTime: await getTypicalTransactionTime(account),
    typicalRecipients: await getFrequentRecipients(account),
    deviceFingerprint: transaction.metadata?.deviceFingerprint,
    ipAddress: transaction.metadata?.ipAddress,
    location: transaction.metadata?.location,

    // External signals
    velocityCheck: await checkTransactionVelocity(account),
    blacklist: await checkBlacklist(transaction.recipient),
  }

  // AI fraud detection
  const analysis = await ai.analyze('fraud-detection', context)

  // Rule-based checks
  const rules = [
    // Amount anomaly
    {
      check: transaction.amount.value > context.typicalAmount * 5,
      risk: 'high',
      reason: 'Amount significantly higher than typical',
    },
    // Velocity check
    {
      check: context.velocityCheck.count > 10,
      risk: 'high',
      reason: 'Too many transactions in short period',
    },
    // New account
    {
      check: context.accountAge < 7,
      risk: 'medium',
      reason: 'New account (less than 7 days old)',
    },
    // Time anomaly
    {
      check: isUnusualTime(new Date(), context.typicalTime),
      risk: 'medium',
      reason: 'Transaction at unusual time',
    },
    // Location anomaly
    {
      check: transaction.metadata?.location && isUnusualLocation(transaction.metadata.location, account),
      risk: 'high',
      reason: 'Transaction from unusual location',
    },
    // Blacklisted recipient
    {
      check: context.blacklist.isListed,
      risk: 'high',
      reason: 'Recipient on fraud blacklist',
    },
  ]

  // Evaluate rules
  const triggeredRules = rules.filter((rule) => rule.check)
  const maxRisk = triggeredRules.reduce((max, rule) => {
    const riskLevel = { low: 1, medium: 2, high: 3 }
    return Math.max(max, riskLevel[rule.risk])
  }, 0)

  const riskLevels = ['none', 'low', 'medium', 'high']
  const ruleBasedRisk = riskLevels[maxRisk]

  // Combine AI and rule-based detection
  const finalRisk = combineRiskScores(analysis.risk, ruleBasedRisk)

  return {
    risk: finalRisk,
    confidence: analysis.confidence,
    reason: [...triggeredRules.map((r) => r.reason), ...analysis.reasons],
    score: analysis.score,
    analysis,
  }
}

// Handle fraud detection
on($.Fraud.detected, async ({ transaction, fraudCheck }) => {
  // Log fraud event
  await db.create($.FraudEvent, {
    transaction: transaction.$id,
    account: transaction.sender.$id,
    riskLevel: fraudCheck.risk,
    confidence: fraudCheck.confidence,
    reasons: fraudCheck.reason,
    detectedAt: new Date(),
    status: 'pending-review',
  })

  // Block account temporarily
  await db.update($.BankAccount, transaction.sender.$id, {
    accountStatus: 'frozen',
    frozenAt: new Date(),
    frozenReason: 'fraud-suspected',
  })

  // Alert customer
  await send($.Email.send, {
    to: transaction.sender.accountHolder.email,
    template: 'fraud-alert',
    priority: 'urgent',
    data: {
      transaction,
      reason: 'Suspicious activity detected on your account',
      action: 'verify',
    },
  })

  await send($.SMS.send, {
    to: transaction.sender.accountHolder.telephone,
    message: `FRAUD ALERT: Suspicious transaction detected. Please verify immediately: ${process.env.APP_URL}/verify/${transaction.$id}`,
  })

  // Alert fraud team
  await send($.Notification.send, {
    to: $.Role.FraudAnalyst,
    priority: 'urgent',
    message: `High-risk transaction detected: ${transaction.identifier}`,
    action: { review: transaction.$id },
  })

  // Create case for investigation
  await $.Case.create({
    $type: 'Case',
    identifier: `FRAUD-${Date.now()}`,
    caseType: 'fraud-investigation',
    subject: transaction.$id,
    priority: 'high',
    status: 'open',
    assignedTo: await getAvailableFraudAnalyst(),
    createdAt: new Date(),
  })
})

4. Payment Processing

Multi-channel payment processing with reconciliation.

// Process ACH payment
async function processACH(params: {
  fromAccount: BankAccount
  toAccount: { routingNumber: string; accountNumber: string }
  amount: number
  description?: string
}) {
  const { fromAccount, toAccount, amount, description } = params

  // Create ACH transaction
  const achTransaction = await $.PaymentAction.create({
    $type: 'PaymentAction',
    identifier: `ACH-${Date.now()}`,

    // Parties
    agent: fromAccount.accountHolder,
    recipient: toAccount,

    // Amount
    amount: {
      $type: 'MonetaryAmount',
      value: amount,
      currency: 'USD',
    },

    // Payment method
    paymentMethod: {
      $type: 'PaymentMethod',
      name: 'ACH',
    },

    // Status
    actionStatus: 'pending',

    // Metadata
    description,
    expectedSettlement: addBusinessDays(new Date(), 2),
    createdAt: new Date(),
  })

  // Submit to ACH processor
  await send($.ACH.submit, {
    transaction: achTransaction,
    fromRouting: fromAccount.routingNumber,
    fromAccount: fromAccount.accountNumber,
    toRouting: toAccount.routingNumber,
    toAccount: toAccount.accountNumber,
    amount,
    description,
  })

  await send($.Payment.submitted, achTransaction)

  return achTransaction
}

// Handle ACH returns
on($.ACH.returned, async ({ transaction, returnCode, reason }) => {
  // Update transaction status
  await db.update($.PaymentAction, transaction.$id, {
    actionStatus: 'failed',
    error: {
      code: returnCode,
      message: reason,
    },
  })

  // Reverse transaction if already settled
  if (transaction.actionStatus === 'completed') {
    await send($.Transaction.reverse, {
      original: transaction,
      reason: 'ach-return',
    })
  }

  // Notify customer
  const account = await db.related(transaction, $.origin, $.BankAccount).then((accounts) => accounts[0])

  await send($.Email.send, {
    to: account.accountHolder.email,
    template: 'payment-returned',
    data: {
      transaction,
      returnCode,
      reason,
    },
  })
})

// Wire transfer processing
async function processWire(params: {
  fromAccount: BankAccount
  toAccount: {
    bankName: string
    routingNumber: string
    accountNumber: string
    swiftCode?: string
    beneficiaryName: string
    beneficiaryAddress: string
  }
  amount: number
  description?: string
}) {
  const { fromAccount, toAccount, amount, description } = params

  // Wire fee
  const wireFee = amount > 10000 ? 0 : 25

  // Check balance including fee
  if (fromAccount.availableBalance.value < amount + wireFee) {
    throw new Error('Insufficient funds (including wire fee)')
  }

  // Create wire transaction
  const wireTransaction = await $.WireTransfer.create({
    $type: 'WireTransfer',
    identifier: `WIRE-${Date.now()}`,

    // Parties
    sender: fromAccount,
    beneficiary: toAccount,

    // Amount
    amount: {
      $type: 'MonetaryAmount',
      value: amount,
      currency: 'USD',
    },
    fee: {
      $type: 'MonetaryAmount',
      value: wireFee,
      currency: 'USD',
    },

    // Status
    status: 'pending-approval',

    // Wire details
    wireType: toAccount.swiftCode ? 'international' : 'domestic',
    description,

    // Expected settlement
    expectedSettlement: addBusinessDays(new Date(), 1),
    createdAt: new Date(),
  })

  // Large wire transfers require approval
  if (amount > 50000) {
    await send($.Wire.requiresApproval, {
      transaction: wireTransaction,
      approver: $.Role.TreasuryManager,
    })
  } else {
    await send($.Wire.submit, wireTransaction)
  }

  return wireTransaction
}

// Card payment processing
async function processCardPayment(params: { cardNumber: string; expiry: string; cvv: string; amount: number; description?: string; merchant: Organization }) {
  const { cardNumber, expiry, cvv, amount, description, merchant } = params

  // Tokenize card
  const cardToken = await send($.Card.tokenize, {
    cardNumber,
    expiry,
    cvv,
  })

  // Create payment
  const payment = await $.PaymentAction.create({
    $type: 'PaymentAction',
    identifier: `CARD-${Date.now()}`,

    // Amount
    amount: {
      $type: 'MonetaryAmount',
      value: amount,
      currency: 'USD',
    },

    // Payment method
    paymentMethod: {
      $type: 'CreditCard',
      token: cardToken,
    },

    // Merchant
    recipient: merchant,

    // Status
    actionStatus: 'pending',

    description,
    createdAt: new Date(),
  })

  // Submit to payment processor
  const result = await send($.PaymentProcessor.charge, {
    token: cardToken,
    amount,
    currency: 'USD',
    description,
    merchant: merchant.$id,
  })

  // Update payment
  await db.update($.PaymentAction, payment.$id, {
    actionStatus: result.status,
    processorResponse: result,
  })

  if (result.status === 'succeeded') {
    await send($.Payment.succeeded, payment)
  } else {
    await send($.Payment.failed, {
      payment,
      error: result.error,
    })
  }

  return payment
}

5. Reconciliation

Automated transaction reconciliation and settlement.

// Daily reconciliation process
async function runDailyReconciliation(date: Date) {
  const startOfDay = startOfBusinessDay(date)
  const endOfDay = endOfBusinessDay(date)

  // Get all transactions for the day
  const transactions = await db.list($.FinancialTransaction, {
    where: {
      transactionDate: {
        $gte: startOfDay,
        $lte: endOfDay,
      },
      transactionStatus: 'completed',
    },
  })

  // Get ledger entries
  const ledgerEntries = await db.list($.LedgerEntry, {
    where: {
      timestamp: {
        $gte: startOfDay,
        $lte: endOfDay,
      },
    },
  })

  // Calculate totals
  const transactionTotals = transactions.reduce(
    (acc, txn) => {
      acc.count++
      acc.credits += txn.amount.value
      acc.debits += txn.amount.value + (txn.transactionFee?.value || 0)
      acc.fees += txn.transactionFee?.value || 0
      return acc
    },
    { count: 0, credits: 0, debits: 0, fees: 0 }
  )

  const ledgerTotals = ledgerEntries.reduce(
    (acc, entry) => {
      if (entry.type === 'credit') {
        acc.credits += entry.amount
      } else {
        acc.debits += entry.amount
      }
      return acc
    },
    { credits: 0, debits: 0 }
  )

  // Check if balanced
  const isBalanced = Math.abs(transactionTotals.credits - ledgerTotals.credits) < 0.01 && Math.abs(transactionTotals.debits - ledgerTotals.debits) < 0.01

  // Create reconciliation report
  const reconciliation = await $.ReconciliationReport.create({
    $type: 'Report',
    name: `Daily Reconciliation - ${date.toISOString().split('T')[0]}`,

    // Period
    datePublished: new Date(),
    reportPeriod: {
      startDate: startOfDay,
      endDate: endOfDay,
    },

    // Results
    isBalanced,
    transactions: transactionTotals,
    ledger: ledgerTotals,
    discrepancies: isBalanced ? [] : findDiscrepancies(transactions, ledgerEntries),

    // Status
    status: isBalanced ? 'balanced' : 'discrepancy',
  })

  if (!isBalanced) {
    // Alert finance team
    await send($.Alert.send, {
      to: $.Role.FinanceTeam,
      priority: 'high',
      message: 'Daily reconciliation discrepancy detected',
      data: { reconciliation },
    })
  }

  await send($.Reconciliation.completed, reconciliation)

  return reconciliation
}

// Bank statement reconciliation
async function reconcileBankStatement(params: { account: BankAccount; statement: BankStatement }) {
  const { account, statement } = params

  // Get internal transactions
  const internalTransactions = await db.list($.FinancialTransaction, {
    where: {
      $or: [{ sender: account.$id }, { recipient: account.$id }],
      transactionDate: {
        $gte: statement.startDate,
        $lte: statement.endDate,
      },
    },
  })

  // Match statement transactions with internal records
  const matches = []
  const unmatchedStatement = []
  const unmatchedInternal = []

  for (const statementTxn of statement.transactions) {
    const match = internalTransactions.find(
      (txn) => Math.abs(txn.amount.value - Math.abs(statementTxn.amount)) < 0.01 && isSameDay(txn.transactionDate, statementTxn.date)
    )

    if (match) {
      matches.push({ statement: statementTxn, internal: match })
    } else {
      unmatchedStatement.push(statementTxn)
    }
  }

  // Find unmatched internal transactions
  for (const internalTxn of internalTransactions) {
    const matched = matches.find((m) => m.internal.$id === internalTxn.$id)
    if (!matched) {
      unmatchedInternal.push(internalTxn)
    }
  }

  // Create reconciliation report
  const report = await $.ReconciliationReport.create({
    $type: 'Report',
    name: `Bank Statement Reconciliation - ${account.accountNumber}`,

    account: account.$id,
    statement: statement.$id,

    matched: matches.length,
    unmatchedStatement: unmatchedStatement.length,
    unmatchedInternal: unmatchedInternal.length,

    isReconciled: unmatchedStatement.length === 0 && unmatchedInternal.length === 0,

    discrepancies: [
      ...unmatchedStatement.map((txn) => ({
        type: 'statement-only',
        transaction: txn,
      })),
      ...unmatchedInternal.map((txn) => ({
        type: 'internal-only',
        transaction: txn,
      })),
    ],

    datePublished: new Date(),
  })

  return report
}

6. Regulatory Compliance & Reporting

Automated compliance reporting for regulatory requirements.

// Generate SAR (Suspicious Activity Report)
async function generateSAR(params: { subject: Person | Organization; activity: string; transactions: FinancialTransaction[]; description: string }) {
  const { subject, activity, transactions, description } = params

  // Create SAR
  const sar = await $.Report.create({
    $type: 'Report',
    name: 'Suspicious Activity Report',

    // Subject information
    subject: subject.$id,
    subjectName: subject.name,
    subjectType: subject.$type,

    // Activity details
    suspiciousActivity: activity,
    description,

    // Transactions
    transactions: transactions.map((txn) => txn.$id),
    totalAmount: transactions.reduce((sum, txn) => sum + txn.amount.value, 0),

    // Dates
    activityStartDate: transactions[0].transactionDate,
    activityEndDate: transactions[transactions.length - 1].transactionDate,
    reportDate: new Date(),

    // Status
    filedWith: 'FinCEN',
    status: 'filed',
  })

  // Submit to FinCEN
  await send($.FinCEN.submitSAR, sar)

  // Log compliance action
  await db.create($.ComplianceLog, {
    action: 'sar-filed',
    report: sar.$id,
    filedBy: 'system',
    filedAt: new Date(),
  })

  return sar
}

// CTR (Currency Transaction Report)
on($.Transaction.completed, async (transaction) => {
  // File CTR for transactions over $10,000
  if (transaction.amount.value > 10000) {
    const ctr = await $.Report.create({
      $type: 'Report',
      name: 'Currency Transaction Report',

      transaction: transaction.$id,
      amount: transaction.amount.value,

      // Parties
      from: transaction.sender.accountHolder,
      to: transaction.recipient.accountHolder,

      // Filing
      reportDate: new Date(),
      filedWith: 'FinCEN',
      status: 'pending',
    })

    await send($.FinCEN.submitCTR, ctr)
  }
})

// OFAC screening
async function screenOFAC(entity: Person | Organization) {
  // Check OFAC sanctions list
  const result = await send($.OFAC.screen, {
    name: entity.name,
    address: entity.address,
    dateOfBirth: entity.birthDate,
    identification: entity.identifier,
  })

  // Save screening result
  await db.create($.OFACScreening, {
    entity: entity.$id,
    screenedAt: new Date(),
    matches: result.matches,
    status: result.matches.length > 0 ? 'blocked' : 'cleared',
  })

  // Block if match found
  if (result.matches.length > 0) {
    await send($.Compliance.block, {
      entity,
      reason: 'ofac-match',
      matches: result.matches,
    })
  }

  return result
}

// Monthly compliance report
async function generateMonthlyComplianceReport(month: Date) {
  const startDate = startOfMonth(month)
  const endDate = endOfMonth(month)

  // Gather compliance metrics
  const metrics = {
    // KYC
    kycVerifications: await db.count($.Person, {
      where: {
        kycVerifiedAt: {
          $gte: startDate,
          $lte: endDate,
        },
      },
    }),

    // AML
    amlScreenings: await db.count($.AMLScreening, {
      where: {
        screenedAt: {
          $gte: startDate,
          $lte: endDate,
        },
      },
    }),
    amlFlags: await db.count($.AMLScreening, {
      where: {
        screenedAt: {
          $gte: startDate,
          $lte: endDate,
        },
        status: 'flagged',
      },
    }),

    // Fraud
    fraudDetections: await db.count($.FraudEvent, {
      where: {
        detectedAt: {
          $gte: startDate,
          $lte: endDate,
        },
      },
    }),
    fraudBlocked: await db.count($.FraudEvent, {
      where: {
        detectedAt: {
          $gte: startDate,
          $lte: endDate,
        },
        status: 'confirmed',
      },
    }),

    // Transactions
    largeTransactions: await db.count($.FinancialTransaction, {
      where: {
        transactionDate: {
          $gte: startDate,
          $lte: endDate,
        },
        'amount.value': { $gt: 10000 },
      },
    }),

    // Reports
    sarsField: await db.count($.Report, {
      where: {
        reportDate: {
          $gte: startDate,
          $lte: endDate,
        },
        name: 'Suspicious Activity Report',
      },
    }),
    ctrsFiled: await db.count($.Report, {
      where: {
        reportDate: {
          $gte: startDate,
          $lte: endDate,
        },
        name: 'Currency Transaction Report',
      },
    }),
  }

  // Create report
  const report = await $.Report.create({
    $type: 'Report',
    name: `Monthly Compliance Report - ${month.toISOString().slice(0, 7)}`,

    reportPeriod: {
      startDate,
      endDate,
    },

    metrics,

    datePublished: new Date(),
    status: 'final',
  })

  return report
}

7. Financial Insights & Analytics

AI-powered financial insights for customers.

// Generate account insights
async function generateAccountInsights(account: BankAccount) {
  // Gather transaction data
  const transactions = await db.list($.FinancialTransaction, {
    where: {
      $or: [{ sender: account.$id }, { recipient: account.$id }],
      transactionDate: {
        $gte: subMonths(new Date(), 6),
      },
    },
  })

  // AI analysis
  const insights = await ai.analyze('financial-insights', {
    account,
    transactions,
    balance: account.accountBalance.value,
  })

  return {
    // Spending patterns
    spending: {
      total: insights.spending.total,
      average: insights.spending.average,
      categories: insights.spending.byCategory,
      trends: insights.spending.trends,
    },

    // Income
    income: {
      total: insights.income.total,
      sources: insights.income.sources,
      regularity: insights.income.regularity,
    },

    // Savings
    savings: {
      rate: insights.savings.rate,
      trend: insights.savings.trend,
      projection: insights.savings.projection,
    },

    // Recommendations
    recommendations: insights.recommendations,

    // Alerts
    alerts: insights.alerts,

    generatedAt: new Date(),
  }
}

// Budget tracking
async function trackBudget(params: { account: BankAccount; budget: Budget; period: 'monthly' | 'weekly' }) {
  const { account, budget, period } = params

  const startDate = period === 'monthly' ? startOfMonth(new Date()) : startOfWeek(new Date())

  // Get spending by category
  const transactions = await db.list($.FinancialTransaction, {
    where: {
      sender: account.$id,
      transactionDate: { $gte: startDate },
    },
  })

  const spendingByCategory = transactions.reduce((acc, txn) => {
    const category = txn.metadata?.category || 'uncategorized'
    acc[category] = (acc[category] || 0) + txn.amount.value
    return acc
  }, {})

  // Compare to budget
  const budgetStatus = Object.keys(budget.categories).map((category) => {
    const budgeted = budget.categories[category]
    const spent = spendingByCategory[category] || 0
    const remaining = budgeted - spent
    const percentage = (spent / budgeted) * 100

    return {
      category,
      budgeted,
      spent,
      remaining,
      percentage,
      status: percentage > 100 ? 'over' : percentage > 80 ? 'warning' : 'ok',
    }
  })

  // Send alerts for overspending
  for (const status of budgetStatus) {
    if (status.status === 'over') {
      await send($.Alert.send, {
        to: account.accountHolder,
        type: 'budget-exceeded',
        message: `You've exceeded your ${status.category} budget by $${Math.abs(status.remaining).toFixed(2)}`,
      })
    } else if (status.status === 'warning') {
      await send($.Alert.send, {
        to: account.accountHolder,
        type: 'budget-warning',
        message: `You've used ${status.percentage.toFixed(0)}% of your ${status.category} budget`,
      })
    }
  }

  return budgetStatus
}

// Cash flow forecasting
async function forecastCashFlow(account: BankAccount, days: number = 30) {
  // Historical data
  const history = await db.list($.FinancialTransaction, {
    where: {
      $or: [{ sender: account.$id }, { recipient: account.$id }],
      transactionDate: {
        $gte: subDays(new Date(), 90),
      },
    },
  })

  // AI forecasting
  const forecast = await ai.predict('cash-flow', {
    account,
    history,
    currentBalance: account.accountBalance.value,
    forecastDays: days,
  })

  return {
    currentBalance: account.accountBalance.value,
    projectedBalance: forecast.projectedBalance,
    expectedIncome: forecast.expectedIncome,
    expectedExpenses: forecast.expectedExpenses,
    confidence: forecast.confidence,
    risks: forecast.risks,
    recommendations: forecast.recommendations,
  }
}

Workflows

Complete Payment Flow

// End-to-end payment workflow
const paymentWorkflow = {
  // 1. Initiate payment
  initiate: async (params: PaymentParams) => {
    const transaction = await processTransaction(params)
    return transaction
  },

  // 2. Validate
  validate: on($.Transaction.created, async (txn) => {
    await validateTransaction(txn)
  }),

  // 3. Fraud check
  fraudCheck: on($.Transaction.created, async (txn) => {
    const fraudResult = await detectFraud(txn)
    if (fraudResult.risk === 'high') {
      await send($.Fraud.detected, { transaction: txn, fraudCheck: fraudResult })
    }
  }),

  // 4. Process
  process: on($.Transaction.process, async (txn) => {
    await executeTransaction(txn)
  }),

  // 5. Settle
  settle: on($.Transaction.completed, async (txn) => {
    await settleTransaction(txn)
  }),

  // 6. Reconcile
  reconcile: setInterval(async () => {
    await runDailyReconciliation(new Date())
  }, 86400000), // Daily
}

Events

// Account events
on($.Account.opened, async (account) => {
  console.log('Account opened:', account.accountNumber)
})

on($.Account.closed, async (account) => {
  console.log('Account closed:', account.accountNumber)
})

// Transaction events
on($.Transaction.completed, async (txn) => {
  console.log('Transaction completed:', txn.identifier)
})

on($.Transaction.failed, async ({ transaction, error }) => {
  console.log('Transaction failed:', transaction.identifier, error)
})

// Fraud events
on($.Fraud.detected, async ({ transaction }) => {
  console.log('Fraud detected:', transaction.identifier)
})

// Compliance events
on($.Compliance.alertTriggered, async (alert) => {
  console.log('Compliance alert:', alert.type)
})

Metrics

// Financial metrics
async function calculateFinancialMetrics() {
  // Total deposits
  const deposits = await db.aggregate($.BankAccount, {
    where: { accountStatus: 'active' },
    aggregations: {
      total: { $sum: 'accountBalance.value' },
      count: { $count: '*' },
    },
  })

  // Transaction volume
  const transactions = await db.aggregate($.FinancialTransaction, {
    where: {
      transactionDate: { $gte: subMonths(new Date(), 1) },
      transactionStatus: 'completed',
    },
    aggregations: {
      volume: { $sum: 'amount.value' },
      count: { $count: '*' },
    },
  })

  // Fee revenue
  const fees = await db.aggregate($.FinancialTransaction, {
    where: {
      transactionDate: { $gte: subMonths(new Date(), 1) },
      transactionStatus: 'completed',
    },
    aggregations: {
      total: { $sum: 'transactionFee.value' },
    },
  })

  return {
    totalDeposits: deposits.total,
    accountCount: deposits.count,
    transactionVolume: transactions.volume,
    transactionCount: transactions.count,
    feeRevenue: fees.total,
  }
}

Best Practices

1. Security

  • Encryption: Encrypt all sensitive data at rest and in transit
  • PCI Compliance: Never store card numbers, CVV, or full PAN
  • Access Control: Implement role-based access with audit logs
  • Multi-Factor Auth: Require MFA for all high-value operations
  • Tokenization: Use tokens for card and bank account data

2. Compliance

  • KYC/AML: Verify all customers before account opening
  • Transaction Monitoring: Monitor all transactions for suspicious activity
  • Record Keeping: Maintain records for regulatory requirements (5-7 years)
  • Regulatory Reporting: File SARs, CTRs, and other reports on time
  • OFAC Screening: Screen all transactions against sanctions lists

3. Fraud Prevention

  • Real-Time Detection: Use AI for real-time fraud detection
  • Behavioral Analysis: Track customer behavior patterns
  • Device Fingerprinting: Track devices and locations
  • Velocity Checks: Monitor transaction frequency and amounts
  • Customer Verification: Require additional verification for high-risk transactions

4. Reliability

  • Idempotency: Ensure all operations are idempotent
  • Atomic Transactions: Use database transactions for consistency
  • Retry Logic: Implement exponential backoff for failed operations
  • Circuit Breakers: Prevent cascading failures
  • Monitoring: Monitor all critical systems 24/7

5. Performance

  • Caching: Cache account balances and frequently accessed data
  • Async Processing: Use queues for non-critical operations
  • Database Optimization: Use proper indexes and query optimization
  • Rate Limiting: Protect APIs from abuse

6. Customer Experience

  • Real-Time Updates: Provide instant transaction notifications
  • Clear Communication: Explain fees, limits, and processes clearly
  • Self-Service: Enable customers to manage accounts independently
  • Support: Provide 24/7 customer support
  • Insights: Give customers visibility into their finances

Complete Implementation

See the full working example at:

Key Takeaways

  1. Security First: Fintech requires the highest security standards
  2. Compliance Always: Regulatory compliance is non-negotiable
  3. Real-Time Processing: Transactions must be fast and reliable
  4. AI for Fraud: Use AI to detect and prevent fraud
  5. Customer Trust: Build trust through transparency and reliability
  6. Audit Everything: Maintain comprehensive audit logs

Next Steps


Questions? Check the patterns or join our Discord