# Hippo-lib - Universal Double Entry Accounting Library

A comprehensive JavaScript library for double-entry accounting system using CouchDB for data storage. **Works in both Node.js and web browsers.**

## Features

- ✅ **Universal compatibility** - Works in Node.js and browsers (with bundlers)
- ✅ **Double-entry accounting system** with automatic balance validation
- ✅ **Chart of Accounts (COA) management** with hierarchy validation and templates
- ✅ **Journal entries** with posting system, force deletion, and reversal capabilities
- ✅ **Trial balance reporting** with formatted output
- ✅ **Account templates** for dynamic vendor, customer, and employee account creation
- ✅ **Journal templates** for standardized transaction patterns
- ✅ **CouchDB integration** with universal HTTP client
- ✅ **Comprehensive ledger management** with centralized balance updates and audit trail
- ✅ **Account filtering by tags** for categorization and search
- ✅ **Date filtering** for ledger entries with CouchDB query optimization
- ✅ **Template key tagging** for audit trails and business intelligence
- ✅ **Date-ordered ledger listing** with CouchDB-level sorting

## Installation

```bash
npm install @debito/hippo-lib
```

## Quick Start

### Node.js Usage

```javascript
const hippoLib = require('@debito/hippo-lib');

// Initialize with database credentials
await hippoLib.init('username', 'password', 'database-name');

// Load Chart of Accounts template
await hippoLib.COA.loadTemplate();

// Create accounts and journal entries
const cash = await hippoLib.Account.findByKey('cash');
await cash.updateBalance(1000);
```

### Browser Usage

**1. Install and bundle with webpack/rollup/vite:**

```bash
npm install @debito/hippo-lib
```

**2. Use in your JavaScript:**

```javascript
// Import with ES modules (bundler required)
import hippoLib from '@debito/hippo-lib';

// Initialize with database credentials
await hippoLib.init('username', 'password', 'database-name');

// All functionality works exactly the same as Node.js
await hippoLib.COA.loadTemplate();
const cash = await hippoLib.Account.findByKey('cash');
await cash.updateBalance(1000);
```

## Configuration

### Simple Initialization

No configuration files needed! Just call the init method:

```javascript
// Node.js with environment variables
require('dotenv').config();
const hippoLib = require('@debito/hippo-lib');

await hippoLib.init(
    process.env.COUCHDB_USERNAME,
    process.env.COUCHDB_PASSWORD,
    process.env.HIPPO_DATABASE_NAME
);
```

### Optional: .env file for Node.js

Create a `.env` file in your project root:

```env
COUCHDB_USERNAME=admin
COUCHDB_PASSWORD=password
HIPPO_DATABASE_NAME=accounting-db
```

# Complete API Reference

## Core Classes

### hippoLib (Main Entry Point)

```javascript
const hippoLib = require('@debito/hippo-lib');

// Initialize the library
await hippoLib.init(username, password, database);

// Get database information
const dbInfo = await hippoLib.getDatabaseInfo();
```

**Available exports:**
- `Account` - Account management class
- `LedgerEntry` - Individual ledger entry class
- `JournalEntry` - Journal entry class
- `COA` - Chart of Accounts utilities
- `TrialBalance` - Trial balance reporting
- `LedgerTemplate` - Account template utilities
- `JournalTemplate` - Journal entry template utilities

### Account Class

Manages individual accounts with balance tracking and validation.

**Properties:**
- `key` - Unique account identifier (string)
- `label` - Display name (string)
- `balance` - Current balance (number, positive for debits in debit accounts)
- `accountType` - Account type ('assets', 'liabilities', 'equity', 'revenue', 'expenses')
- `hierarchy` - Hierarchical path (dot-separated string)
- `tags` - Array of categorization tags

**Static Methods:**

```javascript
// Create new account
const account = await Account.new(key, label, accountType, balance, hierarchy, tags);

// Get account by internal ID
const account = await Account.get(accountId);

// Find account by key (preferred method)
const account = await Account.findByKey(key);

// List all accounts
const accounts = await Account.list();

// List accounts by tags
const vendorAccounts = await Account.listByTag('vendor');
const taggedAccounts = await Account.listByTag(['cash', 'petty']);
```

**Instance Methods:**

```javascript
// Update balance directly (use sparingly - prefer journal entries)
await account.updateBalance(newBalance);

// Update balance from ledger activity (used internally)
await account.updateBalance('debit', 500, 'add');
await account.updateBalance('credit', 300, 'reverse');

// Save changes to database
await account.save();

// Remove account (balance must be zero)
await account.remove();

// Check for unsaved changes
const hasChanges = account.isDirty();

// Get list of changed fields
const changes = account.getChanges();

// Revert unsaved changes
account.rollback();

// Check if account increases with debits
const isDebitAccount = account.isDebitAccount();


// Add ledger entry (used internally)
const ledgerEntry = await account.addLedgerEntry(amount, type, description, journalEntryId);
```

**Example Usage:**

```javascript
// Create a new cash account
const cash = await Account.new(
    'petty-cash',           // key
    'Petty Cash Fund',      // label
    'assets',               // accountType
    500,                    // initial balance
    'assets.cash-bank.petty-cash', // hierarchy
    ['cash', 'petty']       // tags
);

// Update the balance
await cash.updateBalance(750);

// Find an existing account
const existingAccount = await Account.findByKey('petty-cash');
```

### JournalEntry Class

Manages double-entry journal entries with automatic validation.

**Properties:**
- `id` - Journal entry ID (string)
- `lines` - Array of journal lines
- `description` - Entry description (string)
- `date` - Entry date (ISO string)
- `status` - Entry status ('posted', 'reversed', 'deleted')
- `tags` - Array of categorization tags

**Static Methods:**

```javascript
// Create new journal entry
const journal = await JournalEntry.new(description, tags);

// Get journal entry by ID
const journal = await JournalEntry.get(journalId);

// List all journal entries (sorted by date, latest first)
const journals = await JournalEntry.list();

// List with custom sorting
const oldestFirst = await JournalEntry.list({ descending: false });
```

**Instance Methods:**

```javascript
// Add line to journal entry
journal.addLine(accountKey, type, amount, description);

// Validate entry balances (debits = credits)
const isValid = journal.validate();

// Get total debit amount
const debitTotal = journal.getDebitTotal();

// Get total credit amount
const creditTotal = journal.getCreditTotal();

// Get balance (should be 0 for valid entries)
const balance = journal.getBalance();

// Post entry (creates ledger entries, updates account balances)
await journal.post();

// Save metadata changes (description, tags) without affecting ledger
await journal.save();

// Force delete entry and reverse all balances (ADMIN FUNCTION)
await journal.forceDelete(true);

// Reverse entry with offsetting journal entry
const reversingEntry = await journal.reverse('Correction needed');
```

**Example Usage:**

```javascript
// Create a sales transaction
const entry = await JournalEntry.new('Daily cash sales');

// Add debit line (cash received)
entry.addLine('cash', 'debit', 500, 'Cash received from sales');

// Add credit line (revenue recognized)
entry.addLine('sales-revenue', 'credit', 500, 'Product sales revenue');

// Validate and post
if (entry.validate()) {
    await entry.post();
}
```

### LedgerEntry Class

Individual ledger entry records for audit trail.

**Properties:**
- `accountId` - Associated account ID (string)
- `amount` - Entry amount (number, always positive)
- `type` - 'debit' or 'credit'
- `description` - Entry description (string)
- `journalEntryId` - Associated journal entry ID (string)
- `date` - Entry date (ISO string)

**Static Methods:**

```javascript
// Create new ledger entry (usually done automatically)
const ledger = await LedgerEntry.new(accountId, amount, type, description, journalEntryId);

// Get ledger entry by ID
const ledger = await LedgerEntry.get(entryId);

// List entries by account
const entries = await LedgerEntry.listByAccount(accountId);

// List entries by journal entry
const entries = await LedgerEntry.listByJournalEntry(journalEntryId);

// List all ledger entries
const entries = await LedgerEntry.list();

// List with date filtering options
const recentEntries = await LedgerEntry.list({
    startDate: '2025-07-01T00:00:00.000Z',  // From July 1st
    endDate: '2025-07-31T23:59:59.999Z',    // To July 31st
    descending: false                        // Oldest first
});

// Combine account and date filtering
const accountEntries = await LedgerEntry.listByAccount(accountId, {
    startDate: new Date('2025-08-01').toISOString(),
    descending: true  // Latest first (default)
});
```

**Instance Methods:**

```javascript
// Save changes
await ledger.save();

// Check for changes
const hasChanges = ledger.isDirty();

// Get changes
const changes = ledger.getChanges();

// Revert changes
ledger.rollback();
```

## Chart of Accounts (COA) System

### COA Class

Manages hierarchical chart of accounts with templates.

**Static Methods:**

```javascript
// Load COA template and optionally create accounts
const coa = await COA.loadTemplate(templateName = 'default', createAccounts = true);

// Create accounts from template definition
const results = await COA.createAccountsFromTemplate(templateAccounts);

// Store COA template in database
const doc = await COA.storeCOATemplate(template, templateName);

// Load COA from database
const coa = await COA.loadCOAFromDB();

// Validate hierarchy path exists
const node = await COA.validateHierarchyPath(hierarchyPath);

// Check if path represents a group (non-posting) account
const isGroup = await COA.isGroupAccount(hierarchyPath);

// Get hierarchy paths at specific level
const paths = await COA.getHierarchyPaths(parentPath, level);

// Account management in COA
await COA.addAccountToCOA(accountData);
await COA.removeAccountFromCOA(accountKey);
await COA.updateAccountInCOA(accountKey, updates);
```

**Template Structure:**

The COA template includes:
- **Hierarchy:** Nested tree structure with codes and labels
- **Accounts:** Predefined accounts with types and hierarchies
- **Ledger Templates:** Account creation patterns
- **Journal Templates:** Transaction patterns

**Example Usage:**

```javascript
// Load default COA template
await COA.loadTemplate();

// Validate a hierarchy path
const node = await COA.validateHierarchyPath('assets.cash-bank.cash');
console.log(node.label); // "Cash"

// Check if it's a group account
const isGroup = await COA.isGroupAccount('assets.cash-bank');
console.log(isGroup); // true (group accounts can't have transactions)
```

## Template System

### LedgerTemplate Class

Creates standardized accounts for vendors, customers, employees, etc.

**Static Methods:**

```javascript
// Create account from template
const account = await LedgerTemplate.createAccountFromTemplate(templateKey, name, overrides);

// Get template definition
const template = await LedgerTemplate.getTemplate(templateKey);

// List all available templates
const templates = await LedgerTemplate.listTemplates();

// Add custom template
const coa = await LedgerTemplate.addTemplate(templateData);

// Remove template
const coa = await LedgerTemplate.removeTemplate(templateKey);

// Generate key from name
const key = LedgerTemplate.generateKey(name, pattern);

// Generate label from name
const label = LedgerTemplate.generateLabel(name, pattern);

// Utility methods
await LedgerTemplate.printTemplates();
await LedgerTemplate.demonstrateTemplate(templateKey, exampleName);
```

**Built-in Templates:**
- `supplier` - Supplier/vendor accounts (liability type)
- `customer` - Customer receivable accounts (asset type)
- `employee` - Employee payroll accounts (liability type)
- `fixed-asset` - Fixed asset accounts (asset type)

**Example Usage:**

```javascript
// Create a new supplier account
const supplier = await LedgerTemplate.createAccountFromTemplate(
    'supplier',
    'ABC Manufacturing Corp'
);

// Create with custom options
const customer = await LedgerTemplate.createAccountFromTemplate(
    'customer',
    'XYZ Retail Store',
    { 
        balance: 500,
        tags: ['premium', 'corporate']
    }
);

// List available templates
const templates = await LedgerTemplate.listTemplates();
console.log(templates.map(t => `${t.key}: ${t.label}`));
```

### JournalTemplate Class

Creates standardized journal entries from predefined transaction patterns.

**Static Methods:**

```javascript
// Create journal entry from template
const journal = await JournalTemplate.createJournalEntryFromTemplate(
    templateKey,    // Template identifier
    amount,         // Transaction amount
    options,        // Variable substitutions (e.g., {vendor: 'abc-corp'})
    description,    // Entry description
    date           // Optional: ISO date string for historical entries
);
```

**Built-in Journal Templates:**
- `purchase-stock-cash` - Cash purchase from vendor
- `purchase-stock-bank` - Bank payment purchase from vendor
- `purchase-stock-credit` - Credit purchase (accounts payable)
- `vendor-payment-cash` - Cash payment to vendor
- `vendor-payment-bank` - Bank payment to vendor
- `purchase-general-cash` - Generic cash purchase without vendor

**Example Usage:**

```javascript
// Create a cash purchase entry
const purchase = await JournalTemplate.createJournalEntryFromTemplate(
    'purchase-stock-cash',
    1000,
    { vendor: 'abc-manufacturing' },
    'Inventory purchase from ABC Manufacturing'
);

// Create a vendor payment
const payment = await JournalTemplate.createJournalEntryFromTemplate(
    'vendor-payment-bank',
    500,
    { vendor: 'abc-manufacturing' },
    'Payment to ABC Manufacturing'
);
```

## Reporting

### TrialBalance Class

Generates trial balance reports with formatted output.

**Static Methods:**

```javascript
// Generate trial balance as of specific date (default: current date)
const trialBalance = await TrialBalance.asOfDate(date);

// Print formatted trial balance to console
TrialBalance.printToConsole(trialBalance, options);

// Get summary statistics
const summary = TrialBalance.getSummary(trialBalance);
```

**Trial Balance Data Structure:**

```javascript
{
    metadata: {
        asOfDate: "2024-01-01T00:00:00.000Z",
        generatedAt: "2024-01-01T12:00:00.000Z",
        totalAccounts: 25,
        isBalanced: true
    },
    accounts: {
        asset: [
            {key: 'cash', label: 'Cash', balance: 1000, debit: 1000, credit: 0}
        ],
        liability: [...],
        equity: [...],
        revenue: [...],
        expense: [...]
    },
    totals: {
        byGroup: {
            asset: {debit: 5000, credit: 0, count: 10},
            // ... other groups
        },
        overall: {debit: 15000, credit: 15000, difference: 0}
    }
}
```

**Example Usage:**

```javascript
// Generate current trial balance
const tb = await TrialBalance.asOfDate();

// Print formatted report
TrialBalance.printToConsole(tb);

// Get summary data
const summary = TrialBalance.getSummary(tb);
console.log(`Total accounts: ${summary.totalAccounts}`);
console.log(`Is balanced: ${summary.isBalanced}`);
console.log(`Total debits: $${summary.totalDebits}`);
console.log(`Total credits: $${summary.totalCredits}`);

// Show accounts with zero balances
TrialBalance.printToConsole(tb, { showZeroBalances: true });
```

## Constants and Types

### Account Types
```javascript
const { ACCOUNT_TYPES } = require('@debito/hippo-lib/src/constants');

ACCOUNT_TYPES.ASSET     // 'assets'
ACCOUNT_TYPES.LIABILITY // 'liabilities'
ACCOUNT_TYPES.EQUITY    // 'equity'
ACCOUNT_TYPES.REVENUE   // 'revenue'
ACCOUNT_TYPES.EXPENSE   // 'expenses'
```

### Transaction Types
```javascript
const { DEBIT, CREDIT } = require('@debito/hippo-lib/src/constants');

DEBIT   // 'debit'
CREDIT  // 'credit'
```

### Journal Status
```javascript
const { JOURNAL_STATUS } = require('@debito/hippo-lib/src/constants');

JOURNAL_STATUS.POSTED   // 'posted'
JOURNAL_STATUS.REVERSED // 'reversed'
JOURNAL_STATUS.DELETED  // 'deleted'
```

## Database Integration

### Document ID Patterns
- **Accounts:** `account-{key}` (e.g., `account-cash`)
- **Journal Entries:** `jentry_{timestamp}_{random}` (e.g., `jentry_1640995200000_abc123`)
- **Ledger Entries:** `lentry_{timestamp}_{random}` (e.g., `lentry_1640995200000_def456`)
- **COA Settings:** `settings-coa`

### Automatic Indexes
The library creates these CouchDB indexes automatically:
- `ledger-by-date` - Ledger entries sorted by date
- `ledger-by-account` - Ledger entries by account ID
- `ledger-by-journal` - Ledger entries by journal entry ID
- `account-by-name` - Accounts by name

## Journal Entry Lifecycle Management

### Overview
The journal entry system provides comprehensive lifecycle management including posting, reversal, and force deletion capabilities while maintaining proper accounting principles and audit trails.

### Journal Entry Status Flow
```
NEW → POSTED → REVERSED (via reversal entry)
            ↘ DELETED  (via force delete - admin only)
```

### Key Lifecycle Operations

**1. Creating and Posting Entries**
```javascript
// Create new entry (automatically in POSTED status)
const entry = await JournalEntry.new('Sales transaction', ['sales']);
entry.addLine('cash', 'debit', 1000, 'Cash received');
entry.addLine('sales', 'credit', 1000, 'Sales revenue');

// Post the entry (creates ledger entries and updates balances)
await entry.post();
```

**2. Reversing Entries (Accounting Best Practice)**
```javascript
// Create offsetting reversal entry
const reversalEntry = await entry.reverse('Customer returned merchandise');

// Original entry status becomes 'reversed'
// New reversal entry is created with opposite amounts
// Both entries preserved for audit trail
```

**3. Force Deletion (Admin Function)**
```javascript
// CAUTION: Breaks audit trail - use only for corrections/cleanup
await entry.forceDelete(true); // Explicit confirmation required

// Removes all ledger entries
// Reverses all account balance changes
// Marks journal entry as 'deleted' (preserves document for audit)
```

**4. Centralized Balance Management**
```javascript
// All balance updates go through Account.updateBalance()
const account = await Account.findByKey('cash');

// Add activity (normal posting)
await account.updateBalance('debit', 500, 'add');

// Reverse activity (for deletions/corrections)
await account.updateBalance('debit', 500, 'reverse');
```

### Audit Trail and Data Integrity

- **Immutable Principle**: Posted entries cannot be modified, only reversed
- **Complete Audit Trail**: All transactions preserved with status tracking
- **Balance Consistency**: Centralized balance management prevents inconsistencies
- **Force Delete Safety**: Requires explicit confirmation and preserves audit trail

### Testing the Lifecycle
```bash
# Run comprehensive lifecycle test
node test/test-journal-entry-lifecycle.js
```

This test validates:
- ✅ Journal entry creation and posting
- ✅ Ledger entry creation and account balance updates
- ✅ Force deletion with balance reversal
- ✅ Complete cleanup and audit trail preservation

## Date Filtering System

### Overview
The date filtering system provides powerful query capabilities for ledger entries with CouchDB-level optimization for performance.

### Key Features
- **CouchDB Query Integration**: Date filters applied at database level using `$gte` and `$lte` operators
- **Backward Compatibility**: All existing code continues to work without changes
- **Flexible Options**: Combine date filtering with other query options
- **Universal Support**: Works with all LedgerEntry list methods

### Date Filtering Options

**Available Parameters:**
- `startDate` - ISO date string (inclusive) - filters entries on or after this date
- `endDate` - ISO date string (inclusive) - filters entries on or before this date  
- `descending` - Boolean (default: true) - sort order for results

**Supported Methods:**
- `LedgerEntry.list(options)`
- `LedgerEntry.listByAccount(accountId, options)`
- `LedgerEntry.listByJournalEntry(journalId, options)`

### Date Filtering Examples

```javascript
// Filter entries from last month
const lastMonth = new Date();
lastMonth.setMonth(lastMonth.getMonth() - 1);
const monthlyEntries = await LedgerEntry.list({
    startDate: lastMonth.toISOString()
});

// Filter entries for specific date range
const julyEntries = await LedgerEntry.list({
    startDate: '2025-07-01T00:00:00.000Z',
    endDate: '2025-07-31T23:59:59.999Z'
});

// Get account-specific entries for date range
const cashAccount = await Account.findByKey('cash');
const cashJulyEntries = await LedgerEntry.listByAccount(cashAccount._doc._id, {
    startDate: '2025-07-01T00:00:00.000Z',
    endDate: '2025-07-31T23:59:59.999Z',
    descending: false  // Oldest first
});

// Filter entries older than specific date
const oldEntries = await LedgerEntry.list({
    endDate: '2025-06-30T23:59:59.999Z'
});
```

### Date Inheritance System

Ledger entries automatically inherit dates from journal entries:

```javascript
// Manual journal entry with custom date
const entry = await JournalEntry.new('Historical entry', ['historical']);
entry._doc.date = '2025-01-15T10:00:00.000Z'; // Set custom date
entry.addLine('cash', 'debit', 1000, 'Historical cash entry');
entry.addLine('sales', 'credit', 1000, 'Historical sales');
await entry.save(); // Ledger entries inherit this date

// Template entry with custom date
const templateEntry = await JournalTemplate.createJournalEntryFromTemplate(
    'purchase-stock-cash',
    500,
    { vendor: 'vendor-key' },
    'Historical purchase',
    '2025-01-20T00:00:00.000Z' // Custom date parameter
);
```

### Account Tag Filtering

Filter accounts by tags for better organization:

```javascript
// Find all vendor accounts
const vendorAccounts = await Account.listByTag('vendor');

// Find accounts with multiple possible tags
const cashAccounts = await Account.listByTag(['cash', 'petty', 'bank']);

// Case-insensitive partial matching
const supplierAccounts = await Account.listByTag('supplier');
```

## Complete Usage Examples

### Basic Accounting Workflow

```javascript
const hippoLib = require('@debito/hippo-lib');

// 1. Initialize
await hippoLib.init('admin', 'password', 'accounting-db');

// 2. Load Chart of Accounts
await hippoLib.COA.loadTemplate();

// 3. Create vendor account from template
const vendor = await hippoLib.LedgerTemplate.createAccountFromTemplate(
    'supplier',
    'Office Supply Corp'
);

// 4. Create purchase using journal template
const purchase = await hippoLib.JournalTemplate.createJournalEntryFromTemplate(
    'purchase-stock-credit',
    250,
    { vendor: vendor.key },
    'Office supplies purchase'
);

// 5. Generate trial balance
const trialBalance = await hippoLib.TrialBalance.asOfDate();
hippoLib.TrialBalance.printToConsole(trialBalance);
```

### Manual Journal Entry Creation

```javascript
// Create a complex journal entry manually
const journal = await hippoLib.JournalEntry.new('Monthly payroll');

// Add multiple lines
journal.addLine('wages-expense', 'debit', 5000, 'Gross wages');
journal.addLine('payroll-taxes-expense', 'debit', 500, 'Employer payroll taxes');
journal.addLine('employee-taxes-payable', 'credit', 1000, 'Employee tax withholdings');
journal.addLine('wages-payable', 'credit', 4500, 'Net wages payable');

// Validate and save
if (journal.validate()) {
    await journal.save();
    console.log('Payroll journal entry posted successfully');
} else {
    console.log('Entry does not balance!');
}
```

### Account Management

```javascript
// Create accounts with hierarchy and tags
const equipment = await hippoLib.Account.new(
    'pos-system',
    'Point of Sale System',
    'assets',
    2500,
    'assets.fixed-assets.equipment.pos-system',
    ['equipment', 'technology', 'depreciable']
);

// Update account properties
equipment.tags.push('critical');
await equipment.save();

// Search and filter accounts
const allAccounts = await hippoLib.Account.list();
const assetAccounts = allAccounts.filter(acc => acc.accountType === 'assets');
const cashAccounts = allAccounts.filter(acc => acc.tags.includes('cash'));
```

## Browser Compatibility

### Supported Bundlers
- ✅ **Webpack** (all versions)
- ✅ **Rollup** 
- ✅ **Parcel**
- ✅ **Browserify**
- ✅ **esbuild**
- ✅ **Vite**

### Browser Requirements
- Modern browsers with ES6+ support
- Fetch API support (or axios polyfill)
- Module bundler for CommonJS imports

### Example React Integration

```jsx
import React, { useEffect, useState } from 'react';
import hippoLib from '@debito/hippo-lib';

function AccountingDashboard() {
    const [accounts, setAccounts] = useState([]);
    const [trialBalance, setTrialBalance] = useState(null);
    const [initialized, setInitialized] = useState(false);

    useEffect(() => {
        async function initializeAccounting() {
            try {
                // Initialize hippo-lib
                await hippoLib.init(
                    process.env.REACT_APP_COUCH_USER,
                    process.env.REACT_APP_COUCH_PASS,
                    process.env.REACT_APP_COUCH_DB
                );
                
                // Load COA template
                await hippoLib.COA.loadTemplate();
                
                // Load accounts and trial balance
                const accountList = await hippoLib.Account.list();
                const tb = await hippoLib.TrialBalance.asOfDate();
                
                setAccounts(accountList);
                setTrialBalance(tb);
                setInitialized(true);
            } catch (error) {
                console.error('Failed to initialize accounting:', error);
            }
        }
        
        initializeAccounting();
    }, []);

    if (!initialized) return <div>Loading accounting system...</div>;

    return (
        <div>
            <h1>Accounting Dashboard</h1>
            
            <section>
                <h2>Accounts ({accounts.length})</h2>
                {accounts.map(account => (
                    <div key={account.key}>
                        <strong>{account.label}</strong>: ${account.balance}
                        <span> ({account.accountType})</span>
                    </div>
                ))}
            </section>
            
            <section>
                <h2>Trial Balance Summary</h2>
                {trialBalance && (
                    <div>
                        <p>Total Debits: ${trialBalance.totals.overall.debit}</p>
                        <p>Total Credits: ${trialBalance.totals.overall.credit}</p>
                        <p>Balanced: {trialBalance.metadata.isBalanced ? '✅' : '❌'}</p>
                    </div>
                )}
            </section>
        </div>
    );
}

export default AccountingDashboard;
```

## Data Storage

This library uses CouchDB for data persistence. Make sure you have a CouchDB instance running and accessible.

**CouchDB Setup:**
1. Install CouchDB locally or use a cloud service
2. Create a database for your application
3. Configure authentication credentials
4. Set CORS settings for browser access (if needed)

## Testing

Run the test suite:

```bash
# Run comprehensive test suite
npm test

# Individual tests
node test/test-clean.js                    # General accounting operations
node test/test-trial-balance.js            # Trial balance functionality
node test/test-coa-load.js                 # COA template loading
node test/test-accounts-by-tag.js          # Account tag filtering
node test/test-template-tagging.js         # Template key tagging system
node test/test-ledger-date-ordering.js     # Date-ordered ledger listing
node test/test-date-filtering-simple.js    # Date filtering functionality
node test/test-journal-entry-lifecycle.js  # Journal entry posting, deletion, and reversal
node test/test-journal-template.js         # Journal templates
node test/test-ledger-template.js          # Account templates
node test/test-couchdb-driver.js           # CouchDB driver
```

## Complete Browser Guide

For detailed browser usage examples including React, Vue.js, and vanilla JavaScript setups, see **[WEB-USAGE.md](./WEB-USAGE.md)**.

## Contributing

Issues and pull requests are welcome on the project repository.

## License

ISC

---

**@debito/hippo-lib v1.10.0** - Universal double-entry accounting for Node.js and browsers 🎉