Add behavior documentation covering all SSR and legacy SPA pages: - Testing strategy and type definitions (unit/integration/UI) - Dashboard, Invoice, Payment, Transaction, Ledger pages - Company/Settings, POS, Admin, Search, Auth pages - Legacy SPA behavior docs (no UI tests until migrated) - Edge cases, test data requirements, and dependencies per subsystem Total: 3,600+ lines of behavior documentation to guide test authorship.
9.3 KiB
9.3 KiB
Dashboard Behaviors
Overview
The Dashboard is an admin-only, SSR-based overview page that displays financial summary cards across selected clients. It provides at-a-glance visibility into bank account balances, outstanding tasks, recent sales trends, expense breakdowns, and profit/loss summaries. Cards are loaded lazily via HTMX for progressive rendering.
Routes
| Route | Handler | Purpose |
|---|---|---|
GET / |
::page |
Main dashboard page with stub cards |
GET /expense-card |
::expense-card |
Expense pie chart (top 5 accounts, last month) |
GET /pnl-card |
::pnl-card |
Profit & Loss bar chart (last month) |
GET /sales-card |
::sales-card |
Gross sales bar chart (last 14 days) |
GET /bank-accounts-card |
::bank-accounts-card |
Bank account balances and sync status |
GET /tasks-card |
::tasks-card |
Unpaid invoices and uncategorized transactions |
Behaviors
Unit Test Behaviors
extract-client-idsreturns intersection of user's allowed clients and requested clientsis-admin?returns true only whenuser/roleequals"admin"- Client trimming takes only first 20 clients from the valid set
clients-trimmed?is true when the count of trimmed clients differs from valid clients- Bank account card excludes accounts with
bank-account-type/cash - Bank account card displays ledger balance formatted as
$X,XXX.XX - Bank account card shows sync timestamp in
standard-timeformat when present - Sales chart queries use ISO date range from 14 days ago to tomorrow
- Expense pie chart queries use date range from 1 month ago to tomorrow
- P&L card aggregates accounts into
:salesand:cogs :payroll :controllable :fixed-overhead :ownership-controllablecategories - Tasks card queries invoices with
invoice-status/unpaidand transactions withtransaction-approval-status/requires-feedback - Tasks card only renders task sections when counts are non-zero
Integration Test Behaviors
- Main page
GET /returns 200 with base layout and 6 stub cards for admin users - Each card endpoint returns 200 with HTML response containing chart canvas or data
- Bank accounts card performs Datomic pull for each client's bank accounts with nested Intuit/Yodlee/Plaid data
- Sales card executes Datomic query summing
sales-order/totalby ISO date - Expense card executes Datomic query summing
invoice-expense-account/amountby account name - P&L card calls GraphQL
get-profit-and-loss-rawwith trimmed client IDs and last-month date range - Tasks card executes two separate Datomic queries for unpaid invoices and uncategorized transactions
- Expense breakdown card (from
company/reports/expense) executes query with optional vendor and account filters - All card endpoints apply
wrap-trim-clientsandwrap-adminmiddleware - Non-admin requests to any dashboard route receive 302 redirect to
/login - Unauthenticated requests receive 302 redirect to
/loginwithredirect-toparameter
UI Test Behaviors (SSR)
Happy Path: Dashboard Loads Successfully
- Admin user navigates to
/ - Page renders with main navigation, client selector, and breadcrumb "Dashboard"
- Six stub cards appear with loading spinners:
- Expenses (pie chart)
- Tasks
- Bank Accounts (tall card, row-span-2)
- Gross Sales, last 14 days (bar chart)
- Profit and Loss, last month (horizontal bar chart)
- Expense breakdown (bar chart, wide card)
- Each stub card triggers
hx-geton load to fetch its content - Cards progressively render with actual data
- User sees bank account balances, task counts, sales chart, expense charts, and P&L summary
Card Interactions
- Bank Accounts card displays each client's name, account name, ledger balance, and last sync time
- When a bank account has Intuit/Yodlee/Plaid sync, the external balance and sync time display alongside the ledger balance
- Yodlee accounts additionally show "Pending Txs" with pending balance
- Tasks card shows "Pay now" link for unpaid invoices (links to unpaid invoices page with
date-range=year) - Tasks card shows "Review now" link for uncategorized transactions (links to requires-feedback transactions page)
- Expense breakdown card has Vendor and Account typeahead filters
- Changing Vendor or Account filter triggers HTMX request to reload the breakdown chart with filtered data
- Expense breakdown chart updates URL via
hx-push-urlwith query params
Client Selection Effects
- User selects different clients from the client dropdown
- Page triggers
clientSelectedevent on body - HTMX swaps
#app-contentswith fresh dashboard content for newly selected clients - All cards re-fetch with new client context
- If more than 20 clients selected, a yellow warning banner appears: "Warning: These reports are only for twenty of the selected customers. Please select a specific customer to see more detail."
Edge Cases
No Clients Selected
- Dashboard page renders but all cards show empty state
- Bank Accounts card renders empty list
- Sales chart shows empty bar chart with no data points
- Expense pie chart shows empty pie chart
- P&L card shows zero income and expenses
- Tasks card shows no task notifications (sections hidden when count is zero)
Many Clients (Trimming Warning)
- When user has access to more than 20 clients and selects all, only first 20 are used
- Yellow warning banner displays below breadcrumb
- All card queries execute against trimmed client set only
- Warning persists across client selection changes until fewer than 21 clients selected
No Data for Date Ranges
- Sales chart (14-day window): Empty chart renders with no bars when no sales orders exist
- Expense pie chart (last month): Empty pie chart renders when no invoices with expense accounts exist
- P&L card: Shows
$0.00for both income and expenses - Tasks card: No task sections render (conditional on non-zero counts)
- Bank Accounts: Accounts still display with zero/null balances if they exist but have no transactions
Error Loading Individual Cards
- Each card loads independently via separate HTMX request
- Failure in one card endpoint does not prevent other cards from loading
- Stub card shows spinner until successful response or timeout
- Server errors in card endpoints return appropriate HTTP status without breaking page layout
Permissions (Admin vs User)
- Only users with
user/role = "admin"can access dashboard routes - Non-admin authenticated users receive 302 redirect to
/login - Unauthenticated users receive 302 redirect to
/loginwithredirect-toparameter - Admin role is verified by
wrap-adminmiddleware before any data queries execute
Bank Account Sync States
- Account with no external sync (Intuit/Yodlee/Plaid): Shows only ledger balance and sync time
- Account with Intuit sync: Shows Intuit balance and last synced timestamp
- Account with Yodlee sync: Shows available balance, last synced timestamp, and pending balance
- Account with Plaid sync: Shows Plaid balance and last synced timestamp
- Missing/null balances display as
$0.00
Test Data Requirements
Users
- Admin user (
:user/role "admin") with access to multiple clients - Non-admin user (
:user/role "user") to test permission denial
Clients (minimum 2, ideally 25+)
- Client with
client/nameand at least one bank account - Mix of clients with Intuit, Yodlee, and Plaid synced accounts
- Client with
:bank-account-type/cashaccount (should be excluded from display)
Bank Accounts
- Bank account with
:bank-account/current-balanceand:bank-account/current-balance-synced - Bank account linked to Intuit (
:bank-account/intuit-bank-account) - Bank account linked to Yodlee (
:bank-account/yodlee-accountwith available + pending balance) - Bank account linked to Plaid (
:bank-account/plaid-account)
Sales Orders
- Sales orders dated within last 14 days with
:sales-order/total - Sales orders dated outside 14-day window (should not appear)
Invoices
- Invoices with
:invoice/expense-accounts(with:invoice-expense-account/amountand:account/name) within last month - Invoices with
:invoice/status :invoice-status/unpaidwithin last year - Invoices with
:invoice/outstanding-balance - Voided invoices (should be excluded from expense breakdown)
Transactions
- Transactions with
:transaction/approval-status :transaction-approval-status/requires-feedbackwithin last year - Transactions with
:transaction/amount
P&L Data
- Chart of accounts with categories
:sales,:cogs,:payroll,:controllable,:fixed-overhead,:ownership-controllable - Account balances within last month for selected clients
Dependencies
External Services
- Datomic: All card data queried from Datomic database
- GraphQL endpoint: P&L card calls
get-profit-and-loss-raw(Lacinia GraphQL) - Intuit/Yodlee/Plaid: Bank account sync data for external balances (data stored in Datomic)
Frontend Libraries
- HTMX: Progressive card loading via
hx-get/hx-trigger/hx-swap - Chart.js: Canvas-based chart rendering (bar, pie, horizontal bar charts)
- Alpine.js: Chart data binding via
x-data/x-initattributes
Middleware Stack
wrap-admin: Enforces admin-only accesswrap-client-redirect-unauthenticated: Handles auth redirectswrap-trim-clients: Limits client scope to 20wrap-hydrate-clients: Populates client data in request