- Add role management to "By User" tab
- Show all users with roles and/or direct permissions
- Add ability to assign/revoke roles from users
- Display role chips as clickable and removable
- Add "Assign Role" button for each user
- Fix account_id validation error in permission granting
- Extract account_id string from Quasar q-select object
- Apply fix to grantPermission, bulkGrantPermissions, and addRolePermission
- Fix role-based permission checking for expense submission
- Update get_user_permissions_with_inheritance() to include role permissions
- Ensures users with role-based permissions can submit expenses
- Improve Vue reactivity for role details dialog
- Use spread operator to create fresh arrays
- Add $nextTick() before showing dialog
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed critical bugs preventing users from seeing accounts through their assigned roles:
1. **Fixed duplicate function definition** (crud.py)
- Removed duplicate auto_assign_default_role() that only took 1 parameter
- Kept correct version with proper signature and logging
- Added get_all_user_roles() helper function
2. **Added role-based permissions to accounts endpoint** (views_api.py)
- Previously only checked direct user permissions
- Now retrieves and combines both direct AND role permissions
- Auto-assigns default role to new users on first access
3. **Fixed permission inheritance logic** (views_api.py)
- Inheritance check now uses combined permissions (direct + role)
- Previously only checked direct user permissions for parents
- Users can now inherit access to child accounts via role permissions
Changes enable proper RBAC functionality:
- Users with "Employee" role (or any role) now see permitted accounts
- Permission inheritance works correctly with role-based permissions
- Auto-assignment of default role on first Castle access
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Handles race condition where user account already exists from initial sync
but without user_id set. When user configures wallet, code now:
- Catches IntegrityError on UNIQUE constraint for accounts.name
- Fetches existing account by name
- Updates user_id if NULL or different
- Returns existing account instead of failing
This fixes the error that occurred when users configured their wallet after
their accounts were created during the initial Beancount sync.
🤖 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>
- Added validation in create_account_permission() to check account status
- Raises ValueError if account is inactive or doesn't exist
- Provides clear error message identifying the inactive account by name
This ensures users cannot be granted permissions on accounts that have
been marked as inactive (soft deleted).
- Updated get_all_accounts() to add include_inactive parameter (default False)
- Updated get_accounts_by_type() to add include_inactive parameter (default False)
- Modified account_sync to use include_inactive=True (needs to see all accounts)
- Default behavior now hides inactive accounts from user-facing API endpoints
This ensures inactive accounts are automatically hidden from users while
still allowing internal operations (like sync) to access all accounts.
- Added update_account_is_active() function in crud.py
- Updated sync_accounts_from_beancount() to:
* Mark accounts in Castle DB but not in Beancount as inactive
* Reactivate accounts that return to Beancount
* Track deactivated and reactivated counts in sync stats
- Improved sync efficiency with lookup maps
- Enhanced logging for deactivation/reactivation events
This completes the soft delete implementation for orphaned accounts.
When accounts are removed from the Beancount ledger, they are now
automatically marked as inactive in Castle DB during the hourly sync.
Integration Components:
1. Manual API Endpoints (admin-only):
- POST /api/v1/admin/accounts/sync (full sync)
- POST /api/v1/admin/accounts/sync/{account_name} (single account)
2. Scheduled Background Sync:
- Hourly background task (wait_for_account_sync)
- Registered in castle_start() lifecycle
- Automatically syncs new accounts from Beancount to Castle DB
3. Auto-sync on User Account Creation:
- Updated get_or_create_user_account() in crud.py
- Uses sync_single_account_from_beancount() for consistency
- Ensures receivable/payable accounts are synced when users register
Flow:
- User associates wallet → creates receivable/payable in Beancount
→ syncs to Castle DB → permissions can be granted
- Admin manually syncs → all Beancount accounts added to Castle DB
- Hourly task → catches any accounts created directly in Beancount
This ensures Beancount remains the source of truth while Castle DB
maintains metadata for permissions and user associations.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit fixes two critical bugs in the user account creation flow:
1. **Always check/create in Fava regardless of Castle DB status**
- Previously, if an account existed in Castle DB, the function would
return early without checking if the Open directive existed in Fava
- This caused accounts to exist in Castle DB but not in Beancount
- Now we always check Fava and create Open directives if needed
2. **Fix Open directive insertion to preserve metadata**
- The insertion logic now skips over metadata lines when finding
the insertion point
- Prevents new Open directives from being inserted between existing
directives and their metadata, which was causing orphaned metadata
3. **Add comprehensive logging**
- Added detailed logging with [ACCOUNT CHECK], [FAVA CHECK],
[FAVA CREATE], [CASTLE DB], and [WALLET UPDATE] prefixes
- Makes it easier to trace account creation flow and debug issues
4. **Fix Fava filename handling**
- Now queries /api/options to get the Beancount file path dynamically
- Fixes "Parameter 'filename' is missing" errors with /api/source
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This change ensures that user-specific accounts are automatically created
in the Fava/Beancount ledger when they are first requested. It checks for
the existence of the account via a Fava query and creates it via an Open
directive if it's missing. This simplifies account management and
ensures that all necessary accounts are available for transactions.
This implementation adds a new `add_account` method to the `FavaClient`
class which makes use of the /add_entries endpoint to create an account
using an Open Directive.
Migrates balance calculation and inventory tracking to
Fava/Beancount, leveraging Fava's query API for all
accounting calculations. This simplifies the core module
and centralizes accounting logic in Fava.
Add account type filtering to Recent Transactions table and fix pagination issue where filters were applied after fetching results, causing incomplete data display.
Database layer (crud.py):
- Add get_journal_entries_by_user_and_account_type() to filter entries by
both user_id and account_type at SQL query level
- Add count_journal_entries_by_user_and_account_type() for accurate counts
- Filters apply before pagination, ensuring all matching records are fetched
API layer (views_api.py):
- Add filter_account_type parameter ('asset' for receivable, 'liability' for payable)
- Refactor filtering logic to use new database-level filter functions
- Support filter combinations: user only, account_type only, user+account_type, or all
- Enrich entries with account_type metadata for UI display
Frontend (index.js):
- Add account_type to transactionFilter state
- Add accountTypeOptions computed property with receivable/payable choices
- Reorder table columns to show User before Date
- Update loadTransactions to send account_type filter parameter
- Update clearTransactionFilter to clear both user and account_type filters
UI (index.html):
- Add second filter dropdown for account type (Receivable/Payable)
- Show clear button when either filter is active
- Update button label from "Clear Filter" to "Clear Filters"
This fixes the critical bug where filtering for receivables would only show a subset of results (e.g., 2 out of 20 entries fetched) instead of all matching receivables. Now filters are applied at the database level before pagination, ensuring users see all relevant transactions.
Implements pagination for the transaction history, enabling users
to navigate through their transactions in manageable chunks. This
improves performance and user experience, especially for users
with a large number of transactions. It also introduces total entry counts.
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.
Automatically creates a user-specific equity account when a user is granted equity eligibility.
This simplifies the process of granting equity and ensures that each eligible user has a dedicated equity account.
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.
Implements a background task that listens for paid invoices
and automatically records them in the accounting system. This
ensures payments are captured even if the user closes their
browser before the client-side polling detects the payment.
Introduces a new `get_journal_entry_by_reference` function to
improve idempotency when recording payments.
Refactors the accounting logic into a clean, testable core module, separating business logic from database operations.
This improves code quality, maintainability, and testability by creating a dedicated `core/` module, implementing `CastleInventory` for position tracking, moving balance calculations to `core/balance.py`, and adding comprehensive validation in `core/validation.py`.
Improves balance assertion creation by handling Decimal types correctly for database insertion.
It also fixes a validation issue in the UI where the expected balance was not correctly validated as a required field and initializes the value to 0.
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.
Ensures that only cleared entry lines are included when
calculating fiat balances by filtering based on the
journal entry's flag. Excludes pending, flagged, and
voided entries
Adds an admin approval workflow for user-submitted expenses. This ensures that only valid expenses affect user balances.
The workflow includes pending expense states, admin approval/rejection actions, balance filtering, and UI updates.
Implements expense approval functionality, allowing superusers to review and approve or reject expense entries.
This includes:
- Filtering account balance calculations and user balance calculations to only include cleared journal entries.
- Adding API endpoints to retrieve pending expense entries and approve/reject them.
- Updating the UI to display pending expenses to superusers and provide actions to approve or reject them.
This ensures better control over expenses within the system.
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.
Enables users to request manual payments from the Castle and provides admin functions to approve or reject these requests.
Introduces the `manual_payment_requests` table and related CRUD operations.
Adds API endpoints for creating, retrieving, approving, and rejecting manual payment requests.
Updates the UI to allow users to request payments and for admins to review pending requests.
Updates journal entry retrieval to filter entries based on
the user's accounts rather than the user ID.
This ensures that users only see journal entries that
directly affect their accounts.
Also displays fiat amount in journal entries if available in
the metadata.
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.
Implements the ability to record receivables (user owes the castle).
Adds API endpoint for creating receivable entries, which includes currency conversion to satoshis if fiat currency is provided.
Integrates a UI component (receivable dialog) for superusers to record debts owed by users, enhancing financial tracking capabilities.
Implements functionality for super users to view a breakdown of outstanding balances for all users.
This includes:
- Adding an API endpoint to fetch all user balances.
- Updating the frontend to display these balances in a table, accessible only to super users.
- Modifying the balance calculation for the current user to reflect the total owed by or to the castle for super users.
This provides super users with a comprehensive view of the castle's financial position.
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.
Updates journal entry creation to store entry line metadata as a JSON string in the database.
Updates entry line retrieval to parse the JSON string back into a metadata object.
This change allows storing more complex data structures in the metadata field.
Removes the `castle.` prefix from database table names in queries, streamlining data access.
Updates authentication to use `WalletTypeInfo` dependency injection for retrieving wallet information. This improves security and aligns with LNBits' authentication patterns. Also modifies the main router's tag to uppercase.