Transaction Management and Linking
Relevant source files
The following files were used as context for generating this wiki page:
- frontend/components/transactions/transaction-table.tsx
- frontend/lib/actions/transactions.ts
- frontend/lib/actions/transaction-links.ts
- frontend/components/transactions/transaction-sheet.tsx
- frontend/lib/actions/csv-import.ts
- frontend/components/transactions/linked-transactions-section.tsx
- frontend/app/(dashboard)/transactions/transactions-client.tsx/transactions/transactions-client.tsx)
The Transaction Management and Linking system provides a comprehensive interface for users to track, categorize, and associate financial movements. This system handles the full lifecycle of a transaction, from ingestion (via manual entry or CSV import) to sophisticated linking logic that allows users to connect expenses with their corresponding reimbursements.
Core Architecture
The system follows a two-service architecture where the frontend (Next.js) handles UI and CRUD operations via Server Actions, while the backend (Python/FastAPI) provides data enrichment and categorization pipelines. Both services share a single PostgreSQL database, with Drizzle ORM serving as the source of truth for the schema.
Sources: CLAUDE.md:10-25, README.md:104-125
Data Flow for Transaction Creation
When a user manually creates a transaction, the frontend triggers a Server Action which proxies the request to the Python backend to ensure the transaction undergoes the standardized enrichment and categorization pipeline.
Transaction Management
The management interface is centered around the TransactionTable, which utilizes TanStack Table for advanced sorting, filtering, and pagination.
Transaction Attributes
Transactions are represented by the TransactionWithRelations interface, which includes associated data for accounts, categories, and recurring details.
| Field | Type | Description |
|---|---|---|
amount | number | The monetary value (negative for debits, positive for credits) |
bookedAt | Date | The timestamp when the transaction was finalized |
transactionType | "debit" | "credit" | Categorization of the movement type |
includeInAnalytics | boolean | Flag to include/exclude from charts and reports |
category | Relation | Associated category (User-assigned or System-assigned) |
transactionLink | Relation | Group ID and role if the transaction is linked |
Sources: frontend/lib/actions/transactions.ts:333-379, frontend/components/transactions/transaction-table.tsx:47-60
Balancing Transfers
A unique feature of the management system is the "Balancing Transfer." These are specialized transactions used to align the calculated digital balance with the actual real-world account balance. When a balancing transfer is created or deleted, the system triggers a recursive balance recalculation for all subsequent account_balances records.
Sources: frontend/lib/actions/transactions.ts:31-118, frontend/lib/actions/transactions.ts:881-912
Transaction Linking
Linking allows users to associate related transactions, such as an initial expense and a later reimbursement. This prevents "double-counting" in analytics and provides a net view of spending.
Linking Logic and Roles
Transactions within a link group are assigned specific roles:
- Primary: The main transaction (usually the largest expense or income).
- Reimbursement: A credit associated with an expense.
- Expense: A debit associated with an income/allowance.
Linking Search and Suggestions
The system provides utility functions to find potential matches for linking based on currency, absolute amount range, and date.
findPotentialReimbursements: Searches for "credit" type transactions to link to an expense.findPotentialExpenses: Searches for "debit" type transactions to link to an income.
Sources: frontend/lib/actions/transaction-links.ts:400-480, frontend/lib/actions/transaction-links.ts:503-585
CSV Ingestion Pipeline
Transactions can be batch-imported via CSV. The pipeline includes an AI-assisted mapping step and a duplicate detection phase.
Import Workflow
- Initialize: The file is uploaded to storage, and an import session is created.
- AI Mapping: The system sends headers and sample rows to OpenAI to guess the column mapping (Date, Amount, Description).
- Preview & Duplicate Detection: The system compares incoming transactions against existing records using a deterministic hash (
generateCsvImportExternalId). - Finalize: Transactions are sent to the backend in batches (default size 500) for final insertion and categorization.
Deterministic ID Generation
To prevent duplicate imports, the system generates a hash based on the account ID, date, amount, description, and merchant. This ensures that even if a file is uploaded multiple times, the same transactions will not be duplicated in the database.
Sources: frontend/lib/actions/csv-import.ts:634-670
Summary
The Transaction Management and Linking system combines robust CRUD operations with intelligent automation. Through the use of balancing transfers, AI-assisted CSV imports, and a flexible transaction linking model, the platform ensures that users maintain an accurate and insightful record of their financial activities. All operations are designed to be atomic, with Server Actions ensuring that the database remains the consistent source of truth across both frontend and backend services.