Files
integreat/docs/testing/behaviors/transaction.md
Bryce d627e3c5d0 refactor(all): rewrite all behavior docs in table format with checkboxes
Rewrite all 11 remaining behavior documents to match the streamlined
invoice.md format:

- dashboard.md: 250 lines, 62 behaviors
- payment.md: 260 lines, behaviors for list, void, check printing, ACH
- transaction.md: 310 lines, list, import, admin insights
- ledger.md: 519 lines, entries, P&L, balance sheet, cash flows
- company.md: 320 lines, profile, 1099s, Plaid/Yodlee, reports
- admin.md: 494 lines, clients, accounts, vendors, rules, jobs, history
- pos.md: 405 lines, sales, deposits, tenders, refunds, shifts
- search-indicators.md: 167 lines, search modal, indicators
- auth.md: 184 lines, login, logout, impersonation, sessions
- outgoing-invoice.md: 192 lines, create, line items, PDF
- legacy-spa.md: 340 lines, all legacy pages (docs only)

All documents now use:
- Testing Patterns section with reusable abstractions
- Numbered tables: # | Behavior | Test Strategy | Status
- It should... behavior descriptions
- Checkboxes [ ]/[x] for tracking implementation
- Cross-Cutting Behaviors for permissions, lock dates, etc.
- Test Data Requirements tables
- Existing Tests to Preserve sections

Total: 3,844 lines of behavior documentation across 12 subsystem docs.
2026-05-04 13:48:51 -07:00

19 KiB

Transaction Behaviors

Overview

Transactions represent bank account activity imported from external sources (Plaid, Yodlee, Intuit). The SSR transaction pages provide an HTMX-based grid view for browsing, filtering, and exporting transactions, plus an admin insights page for AI-assisted vendor/account coding.

Testing Philosophy

  • Prefer unit tests for pure business logic (calculations, validations, transformations)
  • Use integration tests for database interactions and cross-system flows
  • Use UI tests only for end-to-end happy paths that touch multiple pages
  • Every behavior must be user-visible; no tests for implementation details

Testing Patterns

Pattern: Grid Page Behaviors

Most list pages in Integreat follow the same pattern:

  1. Fetch IDs via Datomic query with filters
  2. Hydrate results via pull-many
  3. Render table with sortable columns
  4. Support selection (individual / all / all-filtered)
  5. Action buttons appear conditionally based on permissions and selection state

Test implications: Validate the query generation, not the rendering. UI tests only need to verify one filter and one sort work end-to-end.

Pattern: Admin Insights Behaviors

Insights pages display AI recommendations for coding transactions:

  1. Fetch unapproved transactions with outcome-recommendation data
  2. Display recommendation buttons sorted by frequency
  3. Allow approving (coding) or rejecting recommendations inline
  4. Use infinite scroll instead of pagination

Test implications: Unit test the recommendation sorting and filtering logic. Integration test the approve/reject endpoints. UI test the infinite scroll and animation behaviors.

Pattern: Permission Gates

Every mutating operation checks:

  1. assert-can-see-client — user has access to the client
  2. assert-not-locked — transaction date >= client locked-until or bank account start-date
  3. can? — user has the specific permission for the activity

Test implications: Integration test each gate independently. UI tests only verify the happy path with a permitted user.


Transaction List Page

Display Behaviors

# Behavior Test Strategy Status
1.1 It should display a table with columns: Client, Vendor, Description, Date, Amount, Links UI [ ]
1.2 It should hide the Client column when only one client with one location is selected Integration [ ]
1.3 It should display the description from description-original in the Description column UI [ ]
1.4 It should fall back to description-simple in italics in the Vendor column when no vendor is assigned UI [ ]
1.5 It should render dates in MM/DD/YYYY format UI [ ]
1.6 It should right-align amounts and format them as $X,XXX.XX UI [ ]
1.7 It should display a links dropdown with links to associated Payment page or Client Overrides UI [ ]
1.8 It should show checkboxes for bulk selection on each row UI [ ]
1.9 It should group table rows by vendor name (or "No vendor") when sorted by Vendor Integration [ ]
1.10 It should show the grid title "Transaction" and entity name "register" UI [ ]
1.11 It should display a breadcrumb showing "Transactions" linking to the list page UI [ ]

Filtering Behaviors

# Behavior Test Strategy Status
2.1 It should filter transactions by vendor typeahead selection Integration [ ]
2.2 It should filter transactions by bank account via radio card selector with "All" plus client's bank accounts Integration [ ]
2.3 It should dynamically reload the bank account filter when the clientSelected event fires Integration [ ]
2.4 It should filter transactions by date range (start/end dates) Integration [ ]
2.5 It should filter transactions by description with 1000ms debounced search Integration [ ]
2.6 It should filter transactions by amount range (min/max) Integration [ ]
2.7 It should support exact-match navigation to a specific transaction by ID, bypassing other filters Integration [ ]
2.8 It should render the exact-match ID as a removable pill when present in query params UI [ ]
2.9 Given multiple filters are applied, when the user changes one filter, then the table should refresh with the combined filter set Integration [ ]

Sorting Behaviors

# Behavior Test Strategy Status
3.1 It should sort by client name ascending/descending Integration [ ]
3.2 It should sort by vendor name ascending/descending, handling missing vendors by grounding empty string Integration [ ]
3.3 It should sort by description ascending/descending Integration [ ]
3.4 It should sort by date ascending/descending Integration [ ]
3.5 It should sort by amount ascending/descending Integration [ ]
3.6 Given the user clicks a column header twice, then the sort direction should toggle Integration [ ]
3.7 It should default to ascending sort on the implicit sort-default field Integration [ ]

Pagination Behaviors

# Behavior Test Strategy Status
4.1 It should display 25 transactions per page by default Integration [ ]
4.2 It should display the total matching count and sum of all matching amounts Integration [ ]
4.3 It should render pagination controls via the grid helper UI [ ]

Action Behaviors

# Behavior Test Strategy Status
5.1 It should display an "Add Transaction" button (primary color) linking to the new transaction route UI [ ]

CSV Export Behaviors

# Behavior Test Strategy Status
6.1 It should export all filtered results (not just the current page) as CSV Integration [ ]
6.2 It should include CSV headers: Id, Client, Vendor, Description, Date, Amount Integration [ ]
6.3 It should use raw data values instead of formatted display values in the CSV Integration [ ]

New Transaction

Note: Routes are defined in auto-ap.routes.transactions but no handlers are wired in auto-ap.ssr.transaction. The "Add Transaction" button in the grid links to this route, which would currently 404. Legacy client-side new transaction functionality exists in the SPA.

Basic Details

# Behavior Test Strategy Status
7.1 It should display a new transaction form at GET /transaction2/new UI [ ]
7.2 It should allow selecting a location via location selector sub-component UI [ ]
7.3 It should allow selecting an account via account typeahead sub-component UI [ ]
7.4 It should allow adding line items via line item sub-component UI [ ]
7.5 It should submit the new transaction via POST /transaction2/new Integration [ ]

External Import

Note: Routes are defined but handlers are not wired in the SSR transaction namespace. The ledger namespace (auto-ap.ssr.ledger) has a fully implemented external import flow that these routes may mirror.

External Transaction Entry

# Behavior Test Strategy Status
8.1 It should display an external transaction entry page at GET /transaction2/external-new UI [ ]

CSV/Text Import

# Behavior Test Strategy Status
8.2 It should display an import form for CSV/text paste at GET /transaction2/external-import-new UI [ ]
8.3 It should parse pasted data via POST /transaction2/external-import-new/parse Integration [ ]
8.4 It should execute the import via POST /transaction2/external-import-new/import Integration [ ]
8.5 It should deduplicate transactions via SHA-256 synthetic keys during import Unit [ ]
8.6 It should auto-match imported transactions to existing pending payments by check number or amount Integration [ ]
8.7 It should auto-match imported transactions to expected deposits Integration [ ]
8.8 It should auto-code imported transactions via transaction rules Integration [ ]
8.9 It should categorize imports as :import, :extant, :suppressed, :error, or :not-ready Integration [ ]

Admin Insights / Coding

Insights Page Display

# Behavior Test Strategy Status
9.1 It should display the insights page at /transaction/insights for admin users UI [ ]
9.2 It should show the title "Transaction Insights" and breadcrumbs: Transactions > Insights UI [ ]
9.3 It should display a data grid with headers: Client, Account, Date, Description, Amount, Actions UI [ ]
9.4 It should show up to 50 recommendations at a time with no pagination Integration [ ]
9.5 It should implement infinite scroll via hx-trigger="intersect once" on the last row UI [ ]
9.6 It should display "That's the last of 'em!" when no more recommendations are available UI [ ]
9.7 It should show an empty grid when no unapproved transactions have recommendations UI [ ]

Recommendation Rows

# Behavior Test Strategy Status
10.1 It should show unapproved transactions from the last 300 days that have outcome-recommendation data Integration [ ]
10.2 It should display each row with: client code, bank account code, date, description, amount UI [ ]
10.3 It should display the amount as a rounded dollar tag (green for positive, red for negative) UI [ ]
10.4 It should show up to 3 recommendation buttons per row, sorted by frequency (highest count first) Integration [ ]
10.5 It should display each recommendation button as `Vendor Name Account Name` with a count badge UI
10.6 It should render recommendation buttons in :primary color if seen by client, :secondary otherwise UI [ ]

Coding Actions

# Behavior Test Strategy Status
11.1 It should approve and code a transaction via POST /transaction/insights/code/:id Integration [ ]
11.2 It should set the approval status to approved and assign vendor and account when coding Integration [ ]
11.3 It should distribute the amount across valid locations using spread-cents when coding Unit [ ]
11.4 It should re-render the row with live-added class and Alpine.js disappear animation after coding UI [ ]
11.5 It should reject a recommendation via DELETE /transaction/insights/disapprove/:id Integration [ ]
11.6 It should clear outcome-recommendation on the transaction when rejecting Integration [ ]
11.7 It should re-render the row with live-removed class and disappear animation after rejecting UI [ ]
11.8 It should open an explain modal via GET /transaction/insights/explain/:id UI [ ]
11.9 It should display similar transactions from Pinecone vector search in the explain modal Integration [ ]
11.10 It should display Date, Description, Amount, Vendor, Account, and Similarity Score for similar transactions UI [ ]
11.11 It should filter similar transactions to scores > 0.95 Unit [ ]
11.12 It should show the top 10 similar transactions plus the target transaction highlighted UI [ ]
11.13 It should show only the target transaction with no similar matches if Pinecone API fails Integration [ ]

Cross-Cutting Behaviors

Approval Workflow Behaviors

# Behavior Test Strategy Status
12.1 It should set transactions to unapproved status on import Integration [ ]
12.2 It should exclude suppressed transactions from all list queries including GraphQL Integration [ ]
12.3 It should show requires-feedback transactions in the dashboard tasks card Integration [ ]
12.4 It should allow admin-only bulk status changes via GraphQL mutation bulk_change_transaction_status Integration [ ]
12.5 It should block modifying locked transactions (before client/locked-until or bank-account/start-date) Integration [ ]

Coding Behaviors

# Behavior Test Strategy Status
13.1 It should allow coding transactions with one or more expense accounts Integration [ ]
13.2 It should validate that account totals equal 100% of the transaction amount server-side Unit + Integration [ ]
13.3 It should require the location to match the account's fixed location if one is set Integration [ ]
13.4 It should distribute amounts proportionally across all client locations when location is "Shared" Unit [ ]
13.5 It should reserve location "A" for liabilities/equities/assets Integration [ ]
13.6 It should allow admin-only bulk coding via GraphQL mutation bulk_code_transactions Integration [ ]

Bank Account Filtering Behaviors

# Behavior Test Strategy Status
14.1 It should show the bank account filter only when a client is selected UI [ ]
14.2 It should dynamically update the bank account filter via HTMX when clientSelected event fires Integration [ ]
14.3 It should validate that the selected bank account belongs to the current client Integration [ ]
14.4 It should default to "All" if the selected account doesn't belong to the current client Integration [ ]

CSV Export Behaviors

# Behavior Test Strategy Status
15.1 It should use the same filters for CSV export as the table view Integration [ ]
15.2 It should export all matching rows bypassing pagination Integration [ ]
15.3 It should include the ID column in CSV but not in the HTML view Integration [ ]

Payments & Linking Behaviors

# Behavior Test Strategy Status
16.1 It should auto-match transactions to payments by check number or amount on import Integration [ ]
16.2 It should create a cleared payment and set the transaction to approved with Accounts Payable account when linking Integration [ ]
16.3 It should revert the transaction to unapproved and clear payment/accounts when unlinking Integration [ ]
16.4 It should allow a transaction to pay multiple autopay invoices, creating a payment that clears them all Integration [ ]
16.5 It should allow a transaction to pay multiple unpaid invoices for outstanding balances Integration [ ]

Permission Behaviors

# Behavior Test Strategy Status
17.1 It should require :activity :view :subject :transaction permission to view transactions Integration [ ]
17.2 It should require :activity :insights :subject :transaction permission to access the insights page Integration [ ]
17.3 It should restrict bulk status changes to admin only Integration [ ]
17.4 It should restrict bulk coding to admin only Integration [ ]
17.5 It should require power user role with client visibility check to edit transactions Integration [ ]
17.6 It should require power user role to match/unlink transactions Integration [ ]
17.7 It should redirect unauthenticated users to /login for all SSR routes Integration [ ]

Import Processing Behaviors

# Behavior Test Strategy Status
18.1 It should assign client and bank account during import Integration [ ]
18.2 It should set initial status to unapproved on import Integration [ ]
18.3 It should extract check number from description if present during import Unit [ ]
18.4 It should attempt auto-match to pending payment during import Integration [ ]
18.5 It should attempt auto-match to expected deposit during import Integration [ ]
18.6 It should apply transaction rules for auto-coding during import Integration [ ]
18.7 It should apply default vendor if set during import Integration [ ]
18.8 It should deduplicate via SHA-256 of date-bank-account-description-amount-index-client Unit [ ]
18.9 It should skip suppressed transactions on re-import Integration [ ]

Empty State Behaviors

# Behavior Test Strategy Status
19.1 It should render an empty state when no transactions match filters UI [ ]
19.2 It should show $0.00 for sum amount when no transactions match UI [ ]
19.3 It should render pagination controls showing 0 results when no transactions match UI [ ]

Test Data Requirements

Entity Requirements
Users Admin user with :user/role "admin"; power user with access to specific clients; regular user with client visibility restrictions; unauthenticated user
Clients Minimum 2 clients with different locations; client with multiple bank accounts; client with single location (to test client column hiding)
Bank Accounts Bank account with bank-account/name and bank-account/numeric-code; bank account with bank-account/start-date (to test locked transactions); multiple bank accounts under same client
Transactions Transactions with all approval statuses (unapproved, approved, requires-feedback, excluded, suppressed); transactions with and without vendors; transactions with positive and negative amounts; transactions linked to payments; transactions with outcome-recommendation (for insights); transactions with exact-match-id parameter; transactions dated before and after client/locked-until
Vendors Vendor with name for typeahead matching; vendor linked to transactions
Accounts Account with fixed location; account without fixed location; account with numeric code (for insights display)
Payments Pending payment with matching check number and amount; cleared payment linked to transaction

Existing Tests to Preserve

  • test/clj/auto_ap/ssr/transaction_test.clj — Transaction SSR routes and behaviors
  • test/clj/auto_ap/integration/routes/transaction_test.clj — Transaction import routes
  • test/clj/auto_ap/integration/graphql/transactions.clj — GraphQL transaction operations

Dependencies

  • Datomic (primary store, history for unvoid)
  • Pinecone (vector similarity search for transaction insights explain feature)
  • Solr (index updated on transaction changes via solr/touch-with-ledger)
  • HTMX (all SSR interactions: filtering, sorting, pagination, insights coding)
  • Alpine.js (filter state for exact match pill, row disappear animations)