The UI omits currencies so the Open directive is written unconstrained,
but the model defaulted currencies to ["EUR","SATS","USD"], so Pydantic
refilled them and the endpoint passed the constraint through — every
admin-created account got a currency-constrained Open (which would
reject postings in other currencies, the same CAD/GBP/JPY bean-check
class we hit on user accounts). Default to None so omission reaches
add_account and the directive is unconstrained; an explicit list still
works for API callers.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extends get_user_balance_bql and get_all_user_balances_bql to fold
Liabilities:Credit:User-X into the same query as Payable and Receivable.
Credit is the overpay-absorbing liability that libra owes the user going
forward — it carries the same sign as Payable, so the existing fiat
aggregation subtracts it from net obligation without further changes.
Adds UserBalance.account_balances to surface the BQL per-account
breakdown so libra extension UI and webapp can render Payable /
Receivable / Credit as distinct line items. The legacy `accounts` field
stays empty for back-compat with anything reading the older shape.
Prepares for libra-#33 / libra-#41: settlement netting (#14 task) will
write the overflow leg to credit; this changeset makes sure that, the
moment credit exists, the displayed net everywhere already reflects it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Companion to the fava ledger split (aiolabs/server-deploy#4). Super-user
endpoint that adds a new Open directive to accounts/chart.beancount via
fava_client.add_account (explicit target_file), then mirrors the account
into Libra's DB via sync_single_account_from_beancount so permissions can
be granted on it.
Validates the account name against the five Beancount top-level prefixes
(Assets:/Liabilities:/Equity:/Income:/Expenses:) and returns 400 on a bad
prefix.
Per-user accounts (matching :User-xxxxxxxx) keep their existing code path
via crud.get_or_create_user_account, which inherits the inferred target_file
(accounts/users.beancount) from the add_account default.
Backend only -- the LNbits admin UI on top is tracked separately as
aiolabs/libra#30.
Refs: aiolabs/libra#29
New get_user_lifetime_totals_bql() runs tag-filtered BQL queries
(Payable + expense-entry, Receivable + income-entry) to compute
per-user lifetime totals separately from the net balance. Plumbed
through /api/v1/balance and /api/v1/balance/{user_id}; existing
clients keep working (fields default to zero / empty dict).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When a user submits income, the money is physically in *their* pocket,
not the entity's cash drawer. The original income endpoint posted DR
on a configurable payment-method asset account (Cash/Bank/Lightning),
which implicitly assumed the entity already had the funds.
Mirror the expense flow instead: DR Assets:Receivable:User-{id[:8]}
(via get_or_create_user_account), CR the revenue account. The user
now owes the entity until they hand the cash over via the existing
/settle-receivable workflow. With this, the per-user Outstanding
Balances card correctly nets expenses (entity owes user, -liability)
against income receipts (user owes entity, +receivable).
Drops payment_method_account from IncomeEntry — no longer needed.
Mirrors the existing expense submission flow so non-admin users can log
income on behalf of the organization for super-user review. New endpoint
POST /api/v1/entries/income takes invoice-key auth, creates a Beancount
transaction with the pending '!' flag, and reuses the existing
/entries/{id}/approve and /reject endpoints (which match by libra-{id}
link regardless of entry type).
Adds PermissionType.SUBMIT_INCOME granted on revenue accounts (parallel
to SUBMIT_EXPENSE on expense accounts) rather than overloading
SUBMIT_EXPENSE — the two operations target distinct account types and
should be grantable independently. Enforces AccountType.REVENUE on the
income account and AccountType.ASSET on the payment-method account;
fiat currency is required (matches the expense flow's effective
requirement). Income entries get a 'income-entry' tag and an
^inc-{entry_id} link for tracking, and surface in the existing
/entries/pending list for super-user approval.
UI work lives in the standalone webapp, out of scope here.
Closes#9
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implement transaction linking to connect expenses with their settlements,
enabling audit trails and tracking of individual expense reimbursements.
Changes:
- beancount_format.py: Use @@ SATS price notation for BQL queryability,
generate unique ^exp-{id} and ^rcv-{id} links, add #settlement tag
- fava_client.py: Add get_unsettled_entries() to find unlinked expenses
- models.py: Add settled_entry_links field to PayUser/SettleReceivable
- views_api.py: Add GET /users/{id}/unsettled-entries endpoint,
pass settlement links through pay_user and settle_receivable
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements metadata-only accounts (e.g., "Expenses", "Assets") that exist
solely in Castle DB for hierarchical permission management. These accounts
don't exist in Beancount but cascade permissions to all child accounts.
Changes:
**Migration (m003)**:
- Add `is_virtual` BOOLEAN field to accounts table
- Create index idx_accounts_is_virtual
- Insert 5 default virtual parents: Assets, Liabilities, Equity, Income, Expenses
**Models**:
- Add `is_virtual: bool = False` to Account, CreateAccount, AccountWithPermissions
**CRUD**:
- Update create_account() to pass is_virtual to Account constructor
**Account Sync**:
- Skip deactivating virtual accounts (they're intentionally metadata-only)
- Virtual accounts never get marked as inactive by sync
**Use Case**:
Admin grants permission on virtual "Expenses" account → user automatically
gets access to ALL real expense accounts:
- Expenses:Groceries
- Expenses:Gas:Kitchen
- Expenses:Maintenance:Property
- (and all other Expenses:* children)
This solves the limitation where Beancount doesn't allow single-level accounts
(e.g., bare "Expenses" can't exist in ledger), but admins need a way to grant
broad access without manually selecting dozens of accounts.
Hierarchical permission inheritance already works via account_name.startswith()
check - virtual accounts simply provide the parent nodes to grant permissions on.
🤖 Generated with Claude Code (https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
New Features:
- BulkGrantPermission model: Grant same permission to multiple users
- BulkGrantResult model: Detailed success/failure results
- POST /api/v1/admin/permissions/bulk-grant endpoint
This simplifies the admin workflow for granting the same account
permission to multiple users at once (e.g., onboarding a team).
The endpoint validates the account exists and is active, then grants
the permission to each user, collecting successes and failures to
return a detailed result.
Related: UI-IMPROVEMENTS-PLAN.md Phase 1
- Migration m002: Add is_active column to castle_accounts table
- Updated Account and AccountWithPermissions models with is_active field
- Default value: TRUE (all existing accounts remain active)
- Index added for performance on is_active queries
Next steps (to be completed):
- Update account sync to mark orphaned accounts as inactive
- Filter inactive accounts in get_all_accounts queries
- Prevent permissions from being granted on inactive accounts
- Add API endpoint to list/reactivate orphaned accounts
This implements soft delete strategy where accounts removed from
Beancount are marked inactive rather than deleted, preserving
historical data and permissions while preventing new activity.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Updates journal entry flags to align with Beancount's limited flag support.
Beancount only uses cleared (*) and pending (!) flags.
Removes the VOID and FLAGGED flags and recommends using tags instead
(e.g., "! + #voided" for voided entries, "! + #review" for flagged entries).
Updates the API to reflect this change, removing the ability to directly
"reject" an expense entry via the void flag. Instead, instructs users to
add the #voided tag in Fava.
Updates reconciliation summary to count entries with voided/review tags
instead of voided/flagged flags.
Refactors account balance retrieval to fetch data from Fava/Beancount
for improved accounting accuracy.
Updates user balance retrieval to use Fava/Beancount data source.
Updates Castle settings ledger slug name.
Adds settings to the Castle extension for integration
with a Fava/Beancount accounting system. This enables
all accounting operations to be managed through Fava.
It includes settings for the Fava URL, ledger slug,
and request timeout.
Refactors the data model to use a single 'amount' field for journal entry lines, aligning with the Beancount approach.
This simplifies the model, enhances compatibility, and eliminates invalid states.
Includes a database migration to convert existing debit/credit columns to the new 'amount' field.
Updates balance calculation logic to utilize the new amount field for improved accuracy and efficiency.
Adds a comment to the `equity_account_name` field in the
`CreateUserEquityStatus` model, clarifying that it is
auto-generated if not provided.
This improves clarity for developers using the API.
Adds an account permissioning system to allow granular control over account access.
Introduces the ability to grant users specific permissions (read, submit_expense, manage) on individual accounts. This includes support for hierarchical permission inheritance, where permissions on parent accounts cascade to child accounts.
Adds new API endpoints for managing account permissions, including granting, listing, and revoking permissions.
Integrates permission checks into existing endpoints, such as creating expense entries, to ensure that users only have access to the accounts they are authorized to use.
Fixes#33 - Implements role based access control
Implements functionality to manage user equity eligibility, allowing admins to grant and revoke access.
Adds database migration, models, CRUD operations, and API endpoints for managing user equity status.
This feature enables finer-grained control over who can convert expenses to equity contributions.
Validates a user's eligibility before allowing them to submit expenses as equity.
Adds support for on-chain Bitcoin payments by:
- Introducing a new `Assets:Bitcoin:OnChain` account.
- Updating the `SettleReceivable` and `PayUser` models to include `txid` for storing transaction IDs.
- Modifying the API endpoints to handle `btc_onchain` as a valid payment method and associate it with the new account.
This allows tracking on-chain Bitcoin transactions separately from Lightning Network payments.
Adds a date field to expense entries for better tracking and reporting.
This allows users to specify the date of the expense transaction,
providing more accurate financial records.
Implements the ability for the super user (Castle) to pay other users for expenses or liabilities.
Introduces a new `PayUser` model to represent these payments, along with API endpoints to process and record them.
Integrates a "Pay User" button into the user list, allowing the super user to initiate payments through either lightning or manual methods (cash, bank transfer, check).
Adds UI elements and logic for handling both lightning payments (generating invoices and paying them) and manual payment recording.
This functionality allows Castle to manage and settle debts with its users directly through the application.
Adds support for settling receivables with fiat currencies
like EUR and USD, in addition to sats.
Updates the settlement dialog to handle fiat amounts and
exchange rates, defaulting to cash payment when a fiat balance
exists.
Modifies the API to accept currency and amount_sats parameters
and adjust the journal entry accordingly, converting the fiat amount
to minor units (e.g., cents) for accounting purposes.
Allows administrators to generate payment invoices on behalf of specific users.
This is useful for handling settlement invoices in certain scenarios.
The changes include:
- Adding a `user_id` field to the generate payment invoice request model
- Updating the API endpoint to accept the `user_id` parameter
- Implementing checks to ensure only superusers can generate invoices for other users
- Updating the memo and extra data to reflect the target user
Implements a "Settle Receivable" feature for super users to record manual payments from users who owe money.
Introduces a dialog for inputting payment details (amount, method, description, reference), triggers an API call to record the transaction, and updates user balances and transaction history.
This is for non-lightning payments like cash, bank transfers, or checks.
Adds balance assertion functionality to enable admins to verify accounting accuracy.
This includes:
- A new `balance_assertions` table in the database
- CRUD operations for balance assertions (create, get, list, check, delete)
- API endpoints for managing balance assertions (admin only)
- UI elements for creating, viewing, and re-checking assertions
Also, reorders the implementation roadmap in the documentation to reflect better the dependencies between phases.
Implements core improvements from Phase 1 of the Beancount patterns adoption:
- Uses Decimal for fiat amounts to prevent floating point errors
- Adds a meta field to journal entries for a full audit trail
- Adds a flag field to journal entries for transaction status
- Migrates existing account names to a hierarchical format
This commit introduces a database migration to add the `flag` and `meta` columns to the `journal_entries` table. It also includes updates to the models, CRUD operations, and API endpoints to handle the new fields.
Extends user balance information to include fiat currency balances,
calculated based on entry line metadata and account types.
This allows for a more comprehensive view of user balances,
including both satoshi and fiat currency holdings.
Updates the castle index template and API to display fiat balances.
Adds functionality for users to pay their Castle balance by generating and paying a Lightning invoice.
This includes:
- Adding API endpoints for invoice generation and payment recording.
- Updating the frontend to allow users to initiate the invoice payment process.
- Passing the wallet's `inkey` to the frontend for payment status checks.
Implements a feature that allows users to pay their outstanding balance via Lightning.
The changes include:
- Adds the UI elements for invoice generation and display, including QR code.
- Integrates backend endpoints to generate and record payments.
- Adds polling mechanism to track payments and update balance.
- Creates new database models to support manual payment requests.
Updates the receivable entry model and related API endpoints to use the user's ID instead of the user's wallet ID.
This change simplifies user identification and ensures consistency throughout the application.
Allows users to configure their own wallet ID, enabling
the system to track expenses and receivables on a per-user basis.
Introduces new database table, models, API endpoints, and UI elements
to manage user-specific wallet settings.
Adds functionality to configure the Castle extension, including a wallet ID.
This allows administrators to customize the extension's behavior by specifying a dedicated wallet for castle operations.
Extends expense entry functionality to support fiat currencies.
Users can now specify a currency (e.g., EUR, USD) when creating expense entries. The specified amount is converted to satoshis using exchange rates. The converted amount and currency information are stored in the journal entry metadata. Also adds an API endpoint to retrieve allowed currencies and updates the UI to allow currency selection when creating expense entries.