Skip to main content

Balance Reconciliation System

This document describes the automatic balance reconciliation system that monitors for discrepancies between opportunity balances and blockchain deposits.

Overview

The system periodically checks all opportunity balances against confirmed blockchain deposits. When discrepancies are found, admins are notified through the admin notification system.

Background Job

Location

  • Job script: lib/jobs/checkBalanceDiscrepancies.ts
  • API trigger: POST /api/admin/jobs/check-discrepancies

How It Works

  1. Fetches all opportunity balances with their confirmed deposits
  2. Calculates the sum of confirmed deposits for each balance
  3. Compares the sum against the totalInvested field
  4. Reports any discrepancies greater than $0.01 (accounting for floating point precision)

Cron Job Setup

To run the balance discrepancy check automatically, add this to your crontab:

# Run every hour
0 * * * * cd /var/www/opportunitydao && npx tsx lib/jobs/checkBalanceDiscrepancies.ts >> /var/log/reprise/balance-check.log 2>&1

# OR run every 6 hours
0 */6 * * * cd /var/www/opportunitydao && npx tsx lib/jobs/checkBalanceDiscrepancies.ts >> /var/log/reprise/balance-check.log 2>&1

# OR run daily at 3 AM
0 3 * * * cd /var/www/opportunitydao && npx tsx lib/jobs/checkBalanceDiscrepancies.ts >> /var/log/reprise/balance-check.log 2>&1

Note: Adjust the path to match your installation directory.

Using Systemd Timer (Alternative)

Create a systemd service and timer for more robust scheduling:

Service file: /etc/systemd/system/reprise-balance-check.service

[Unit]
Description=Reprise Balance Reconciliation Check
After=network.target

[Service]
Type=oneshot
User=www-data
WorkingDirectory=/var/www/opportunitydao
ExecStart=/usr/bin/npx tsx lib/jobs/checkBalanceDiscrepancies.ts
StandardOutput=journal
StandardError=journal

Timer file: /etc/systemd/system/reprise-balance-check.timer

[Unit]
Description=Run Reprise Balance Check Hourly
Requires=reprise-balance-check.service

[Timer]
OnCalendar=hourly
Persistent=true

[Install]
WantedBy=timers.target

Enable and start the timer:

sudo systemctl enable reprise-balance-check.timer
sudo systemctl start reprise-balance-check.timer
sudo systemctl status reprise-balance-check.timer

Admin Notifications

Notification System

The admin notification API (/api/admin/notifications) automatically includes:

  • pendingDeposits - Count of pending deposits requiring review
  • balanceDiscrepancies - Count of balances with discrepancies
  • hasNotifications - True if either count is greater than 0

Polling Interval

AdminNav polls the notification endpoint every 30 seconds to check for:

  1. New pending deposits
  2. Balance discrepancies

Notification Display

When discrepancies are detected:

  • Desktop: Red badge on user avatar with total notification count
  • Mobile: Red badge on user avatar with total notification count
  • Dropdown Menu: "Balance Discrepancies" link with count badge (both desktop and mobile)
  • Direct Link: Takes admin to /admin/reconcile-balances

Manual Reconciliation

Via UI

  1. Navigate to Tools → Reconcile Balances in admin panel
  2. Review discrepancies with detailed breakdown
  3. Select balances to fix (or use "Reconcile All")
  4. Confirm action to recalculate totalInvested from blockchain deposits

Via API

Check for discrepancies:

GET /api/admin/reconcile-balances

Reconcile specific balances:

POST /api/admin/reconcile-balances
Content-Type: application/json

{
"balanceIds": [1, 2, 3],
"mode": "recalculate"
}

Reconcile all discrepancies:

POST /api/admin/reconcile-balances
Content-Type: application/json

{
"mode": "recalculate"
}

Audit Trail

All reconciliation actions are logged to the audit_log table with:

  • Action: RECONCILE_BALANCE
  • Old values: Original totalInvested, userId, opportunityId
  • New values: Corrected totalInvested, user details, opportunity details, discrepancy amount, reconciled by admin email
  • IP address of admin performing the action

Source of Truth

The blockchain is always the source of truth. The system recalculates totalInvested based on the sum of confirmed blockchain deposits.

Integration with Deposit Processing

The balance check job works alongside the deposit processing job:

  • Deposit Processing (lib/jobs/processDeposits.ts) - Confirms pending deposits
  • Balance Check (lib/jobs/checkBalanceDiscrepancies.ts) - Verifies balance accuracy
# Process deposits every 3 minutes
*/3 * * * * cd /var/www/opportunitydao && npx tsx lib/jobs/processDeposits.ts >> /var/log/reprise/deposits.log 2>&1

# Check balances every hour
0 * * * * cd /var/www/opportunitydao && npx tsx lib/jobs/checkBalanceDiscrepancies.ts >> /var/log/reprise/balance-check.log 2>&1

Troubleshooting

No discrepancies showing but balances seem wrong

  1. Check if deposits are confirmed (status = 'confirmed')
  2. Verify the deposit processor is running
  3. Manually run the balance check job to see console output
  4. Check audit logs for recent reconciliation actions

Discrepancies not appearing in notifications

  1. Verify the admin notification polling is working (check browser console)
  2. Manually call /api/admin/notifications to check the response
  3. Ensure discrepancies are greater than $0.01
  4. Check that the balance check job has run recently

How to run jobs manually

# Change to project directory
cd /var/www/opportunitydao

# Check for discrepancies
npx tsx lib/jobs/checkBalanceDiscrepancies.ts

# Process pending deposits
npx tsx lib/jobs/processDeposits.ts

# Via API (requires admin authentication)
curl -X POST http://localhost:3000/api/admin/jobs/check-discrepancies \
-H "Cookie: auth_token=YOUR_TOKEN"

curl -X POST http://localhost:3000/api/admin/jobs/process-deposits \
-H "Cookie: auth_token=YOUR_TOKEN"

Log Files

Recommended log file locations:

  • /var/log/reprise/balance-check.log - Balance discrepancy checks
  • /var/log/reprise/deposits.log - Deposit processing
  • /var/log/reprise/reconciliation.log - Manual reconciliations (via audit_log table)

Create log directory:

sudo mkdir -p /var/log/reprise
sudo chown www-data:www-data /var/log/reprise
  • lib/jobs/checkBalanceDiscrepancies.ts - Main job script
  • app/api/admin/jobs/check-discrepancies/route.ts - API trigger endpoint
  • app/api/admin/notifications/route.ts - Notification system
  • app/api/admin/reconcile-balances/route.ts - Reconciliation API
  • app/admin/reconcile-balances/page.tsx - Reconciliation UI
  • components/AdminNav.tsx - Notification display
  • lib/audit.ts - Audit logging