libra/MIGRATION_SQUASH_SUMMARY.md
Padreug c174cda48d Rename Castle Accounting extension to Libra
Full identifier rename: module path lnbits.extensions.castle →
lnbits.extensions.libra, DB ext_castle → ext_libra, URL prefix
/castle/ → /libra/, manifest id castle → libra, fava ledger slug
default castle-ledger → libra-ledger, Beancount source metadata
castle-api → libra-api and link prefixes castle-{entry,tx}- →
libra-{entry,tx}-, column castle_wallet_id → libra_wallet_id, all
Python/JS/HTML identifiers (castle_ext, CastleSettings,
castle_reference, castleWalletConfigured, etc.).

Display name "Castle Accounting" → "Libra" (the scales/balance
metaphor — fits double-entry bookkeeping).

No backward compat: production hosts will be force-updated. Old
castle-prefixed Beancount metadata in existing Fava ledgers is
historical; new entries use libra-* prefixes going forward.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 10:24:46 +02:00

7.1 KiB

Libra Migration Squash Summary

Date: November 10, 2025
Action: Squashed 16 incremental migrations into a single clean initial migration

Overview

The Libra extension had accumulated 16 migrations (m001-m016) during development. Since the software has not been released yet, we safely squashed all migrations into a single clean m001_initial migration.

Files Changed

  • migrations.py - Replaced with squashed single migration (651 → 327 lines)
  • migrations_old.py.bak - Backup of original 16 migrations for reference

Final Database Schema

The squashed migration creates 7 tables:

1. libra_accounts

  • Core chart of accounts with hierarchical Beancount-style names
  • Examples: "Assets:Bitcoin:Lightning", "Expenses:Food:Groceries"
  • User-specific accounts: "Assets:Receivable:User-af983632"
  • Includes comprehensive default account set (40+ accounts)

2. libra_extension_settings

  • Libra-wide configuration
  • Stores libra_wallet_id for Lightning payments

3. libra_user_wallet_settings

  • Per-user wallet configuration
  • Allows users to have separate wallet preferences

4. libra_manual_payment_requests

  • User-submitted payment requests to Libra
  • Reviewed by admins before processing
  • Includes notes field for additional context

5. libra_balance_assertions

  • Reconciliation and balance checking at specific dates
  • Multi-currency support (satoshis + fiat)
  • Tolerance checking for small discrepancies
  • Includes notes field for reconciliation comments

6. libra_user_equity_status

  • Manages equity contribution eligibility
  • Equity-eligible users can convert expenses to equity
  • Creates dynamic user-specific equity accounts: Equity:User-{user_id}

7. libra_account_permissions

  • Granular access control for accounts
  • Permission types: read, submit_expense, manage
  • Supports hierarchical inheritance (parent permissions cascade)
  • Time-based expiration support

What Was Removed

The following tables were intentionally NOT included in the final schema (they were dropped in m016):

  • libra_journal_entries - Journal entries now managed by Fava/Beancount (external source of truth)
  • libra_entry_lines - Entry lines now managed by Fava/Beancount

Libra now uses Fava as the single source of truth for accounting data. Journal operations:

  • Write: Submit to Fava via FavaClient.add_entry()
  • Read: Query Fava via FavaClient.get_entries()

Key Schema Decisions

  1. Hierarchical Account Names - Beancount-style colon-separated hierarchy (e.g., "Assets:Bitcoin:Lightning")
  2. No Journal Tables - Fava/Beancount is the source of truth for journal entries
  3. Dynamic User Accounts - User-specific accounts created on-demand (Assets:Receivable:User-xxx, Equity:User-xxx)
  4. No Parent-Only Accounts - Hierarchy is implicit in names (no "Assets:Bitcoin" parent account needed)
  5. Multi-Currency Support - Balance assertions support both satoshis and fiat currencies
  6. Notes Fields - Added notes to balance_assertions and manual_payment_requests for better documentation

Migration History (Original 16 Migrations)

For reference, the original migration sequence (preserved in migrations_old.py.bak):

  1. m001 - Initial accounts, journal_entries, entry_lines tables
  2. m002 - Extension settings table
  3. m003 - User wallet settings table
  4. m004 - Manual payment requests table
  5. m005 - Added flag/meta columns to journal_entries
  6. m006 - Migrated to hierarchical account names
  7. m007 - Balance assertions table
  8. m008 - Renamed Lightning account (Assets:Lightning:Balance → Assets:Bitcoin:Lightning)
  9. m009 - Added OnChain Bitcoin account (Assets:Bitcoin:OnChain)
  10. m010 - User equity status table
  11. m011 - Account permissions table
  12. m012 - Updated default accounts with detailed hierarchy (40+ accounts)
  13. m013 - Removed parent-only accounts (Assets:Bitcoin, Equity)
  14. m014 - Removed legacy equity accounts (MemberEquity, RetainedEarnings)
  15. m015 - Converted entry_lines from debit/credit to single amount field
  16. m016 - Dropped journal_entries and entry_lines tables (Fava integration)

Benefits of Squashing

  1. Cleaner Codebase - Single 327-line migration vs 651 lines across 16 functions
  2. Easier to Understand - New developers see final schema immediately
  3. Faster Fresh Installs - One migration run instead of 16
  4. Better Documentation - Comprehensive comments explain design decisions
  5. No Migration Artifacts - No intermediate states, data conversions, or temporary columns

Fresh Install Process

For new installations:

# Libra's migration system will run m001_initial automatically
# No manual intervention needed

The migration will:

  1. Create all 7 tables with proper indexes and foreign keys
  2. Insert 40+ default accounts with hierarchical names
  3. Set up proper constraints and defaults
  4. Complete in a single transaction

Default Accounts Created

The migration automatically creates a comprehensive chart of accounts:

Assets (12 accounts):

  • Assets:Bank
  • Assets:Bitcoin:Lightning
  • Assets:Bitcoin:OnChain
  • Assets:Cash
  • Assets:FixedAssets:Equipment
  • Assets:FixedAssets:FarmEquipment
  • Assets:FixedAssets:Network
  • Assets:FixedAssets:ProductionFacility
  • Assets:Inventory
  • Assets:Livestock
  • Assets:Receivable
  • Assets:Tools

Liabilities (1 account):

  • Liabilities:Payable

Income (3 accounts):

  • Income:Accommodation:Guests
  • Income:Service
  • Income:Other

Expenses (24 accounts):

  • Expenses:Administrative
  • Expenses:Construction:Materials
  • Expenses:Furniture
  • Expenses:Garden
  • Expenses:Gas:Kitchen
  • Expenses:Gas:Vehicle
  • Expenses:Groceries
  • Expenses:Hardware
  • Expenses:Housewares
  • Expenses:Insurance
  • Expenses:Kitchen
  • Expenses:Maintenance:Car
  • Expenses:Maintenance:Garden
  • Expenses:Maintenance:Property
  • Expenses:Membership
  • Expenses:Supplies
  • Expenses:Tools
  • Expenses:Utilities:Electric
  • Expenses:Utilities:Internet
  • Expenses:WebHosting:Domain
  • Expenses:WebHosting:Wix

Equity:

  • Created dynamically as Equity:User-{user_id} when granting equity eligibility

Testing

After squashing, verify the migration works:

# 1. Backup existing database (if any)
cp libra.sqlite3 libra.sqlite3.backup

# 2. Drop and recreate database to test fresh install
rm libra.sqlite3

# 3. Start LNbits - migration should run automatically
poetry run lnbits

# 4. Verify tables created
sqlite3 libra.sqlite3 ".tables"
# Should show: libra_accounts, libra_extension_settings, etc.

# 5. Verify default accounts
sqlite3 libra.sqlite3 "SELECT COUNT(*) FROM libra_accounts;"
# Should show: 40 (default accounts)

Rollback Plan

If issues are discovered:

# Restore original migrations
cp migrations_old.py.bak migrations.py

# Restore database
cp libra.sqlite3.backup libra.sqlite3

Notes

  • This squash is safe because Libra has not been released yet
  • No existing production databases need migration
  • Historical migrations preserved in migrations_old.py.bak
  • All functionality preserved in final schema
  • No data loss concerns (no production data exists)

Signed off by: Claude Code
Reviewed by: Human operator
Status: Complete