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.
251 lines
11 KiB
Markdown
251 lines
11 KiB
Markdown
# 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.
|
|
|
|
**Testing Philosophy**
|
|
- Prefer unit tests for pure business logic (calculations, formatting, client trimming)
|
|
- Use integration tests for database interactions and cross-system flows (Datomic queries, GraphQL calls)
|
|
- Use UI tests only for end-to-end happy paths and visual states
|
|
- Every behavior must be user-visible; no tests for implementation details
|
|
|
|
---
|
|
|
|
## Testing Patterns
|
|
|
|
### Pattern: Progressive Card Loading
|
|
Dashboard cards follow a progressive loading pattern:
|
|
1. SSR renders stub cards with loading spinners
|
|
2. Each stub triggers an independent HTMX request on load
|
|
3. Card endpoints return HTML fragments that replace the stub content
|
|
4. Cards load independently without blocking each other
|
|
|
|
**Test implications:** Unit test the card query logic. Integration test each card endpoint returns valid HTML. UI test only needs to verify the page loads and cards appear.
|
|
|
|
### Pattern: Client Context Propagation
|
|
All dashboard operations depend on selected clients:
|
|
1. Client selection triggers a page-wide refresh via HTMX
|
|
2. `wrap-trim-clients` middleware limits to 20 clients before queries execute
|
|
3. All card endpoints receive the same trimmed client set
|
|
|
|
**Test implications:** Integration test that changing clients updates all cards. Unit test the trimming logic.
|
|
|
|
### Pattern: Admin Permission Gating
|
|
The dashboard is restricted to admin users:
|
|
1. `wrap-admin` middleware checks user role before any data access
|
|
2. Non-admin users are redirected before reaching handlers
|
|
3. Middleware is applied consistently to all card endpoints
|
|
|
|
**Test implications:** Integration test each endpoint independently for permission enforcement.
|
|
|
|
---
|
|
|
|
## Dashboard Page
|
|
|
|
### Page Loading Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 1.1 | It should render the main dashboard page with navigation, client selector, and "Dashboard" breadcrumb for admin users | UI | [ ] |
|
|
| 1.2 | It should display six stub cards with loading spinners for progressive rendering | UI | [ ] |
|
|
| 1.3 | It should trigger independent HTMX requests to load each card's content on page load | Integration | [ ] |
|
|
| 1.4 | It should progressively replace stub cards with actual data as responses arrive | UI | [ ] |
|
|
|
|
---
|
|
|
|
## Bank Accounts Card
|
|
|
|
### Display Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 2.1 | It should display each client's name, account name, ledger balance, and last sync time | UI | [ ] |
|
|
| 2.2 | It should exclude bank accounts with cash type from the display | Integration | [ ] |
|
|
| 2.3 | It should format ledger balances as currency ($X,XXX.XX) | Unit + UI | [ ] |
|
|
| 2.4 | It should display the last sync timestamp in standard time format when present | Unit + UI | [ ] |
|
|
| 2.5 | It should display Intuit balance and sync time for Intuit-linked accounts | UI | [ ] |
|
|
| 2.6 | It should display Yodlee available balance, sync time, and pending balance for Yodlee-linked accounts | UI | [ ] |
|
|
| 2.7 | It should display Plaid balance and sync time for Plaid-linked accounts | UI | [ ] |
|
|
| 2.8 | It should display $0.00 for missing or null balances | Unit + UI | [ ] |
|
|
|
|
---
|
|
|
|
## Sales Card
|
|
|
|
### Display Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 3.1 | It should display a bar chart of gross sales for the last 14 days | UI | [ ] |
|
|
| 3.2 | It should render an empty bar chart when no sales orders exist in the date range | UI | [ ] |
|
|
|
|
### Data Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 3.3 | It should query and sum sales order totals by date for the selected clients | Integration | [ ] |
|
|
|
|
---
|
|
|
|
## Expense Card
|
|
|
|
### Display Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 4.1 | It should display a pie chart of the top 5 expense accounts for the last month | UI | [ ] |
|
|
| 4.2 | It should render an empty pie chart when no invoices with expense accounts exist in the date range | UI | [ ] |
|
|
|
|
### Data Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 4.3 | It should sum expense amounts by account name for the selected clients | Integration | [ ] |
|
|
|
|
---
|
|
|
|
## Profit & Loss Card
|
|
|
|
### Display Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 5.1 | It should display income and expenses aggregated by category (sales, COGS, payroll, controllable, fixed overhead, ownership controllable) | UI | [ ] |
|
|
| 5.2 | It should show $0.00 for both income and expenses when no data exists for the period | UI | [ ] |
|
|
|
|
### Data Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 5.3 | It should query P&L data via GraphQL for the selected clients and last month | Integration | [ ] |
|
|
|
|
---
|
|
|
|
## Tasks Card
|
|
|
|
### Display Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 6.1 | It should display the count of unpaid invoices when the count is non-zero | UI | [ ] |
|
|
| 6.2 | It should display the count of uncategorized transactions requiring feedback when the count is non-zero | UI | [ ] |
|
|
| 6.3 | It should provide a "Pay now" link for unpaid invoices linking to the unpaid invoices page with year date range | UI | [ ] |
|
|
| 6.4 | It should provide a "Review now" link for uncategorized transactions linking to the requires-feedback page | UI | [ ] |
|
|
| 6.5 | It should hide task sections entirely when their respective counts are zero | Integration | [ ] |
|
|
|
|
### Data Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 6.6 | It should query Datomic for invoices with unpaid status for the selected clients | Integration | [ ] |
|
|
| 6.7 | It should query Datomic for transactions with requires-feedback approval status for the selected clients | Integration | [ ] |
|
|
|
|
---
|
|
|
|
## Expense Breakdown Card
|
|
|
|
### Display Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 7.1 | It should display a bar chart breaking down expenses by account | UI | [ ] |
|
|
| 7.2 | It should render an empty chart when no expense data exists | UI | [ ] |
|
|
| 7.3 | It should provide Vendor and Account typeahead filters | UI | [ ] |
|
|
|
|
### Data Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 7.4 | It should reload the chart with filtered data when filter selections change | Integration | [ ] |
|
|
| 7.5 | It should update the URL with filter query parameters via hx-push-url | Integration | [ ] |
|
|
| 7.6 | It should exclude voided invoices from the breakdown | Integration | [ ] |
|
|
|
|
---
|
|
|
|
## Filtering Behaviors
|
|
|
|
### Expense Breakdown Filters
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 8.1 | It should filter the expense breakdown chart by vendor selection | Integration | [ ] |
|
|
| 8.2 | It should filter the expense breakdown chart by expense account selection | Integration | [ ] |
|
|
| 8.3 | It should trigger an HTMX request to reload the chart when any filter changes | Integration | [ ] |
|
|
|
|
---
|
|
|
|
## Client Selection Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 9.1 | It should update the dashboard content when the user selects different clients from the dropdown | UI | [ ] |
|
|
| 9.2 | It should trigger a clientSelected event on the body when client selection changes | Integration | [ ] |
|
|
| 9.3 | It should swap the dashboard content area with fresh content for the newly selected clients | Integration | [ ] |
|
|
| 9.4 | It should re-fetch all card data with the new client context | Integration | [ ] |
|
|
| 9.5 | It should limit reports to the first 20 selected clients from the valid set | Unit + Integration | [ ] |
|
|
| 9.6 | It should display a yellow warning banner when more than 20 clients are selected | UI | [ ] |
|
|
| 9.7 | It should persist the warning banner across client selection changes until fewer than 21 clients are selected | UI | [ ] |
|
|
| 9.8 | It should trim the client set before executing any card data queries | Integration | [ ] |
|
|
|
|
---
|
|
|
|
## Error Handling Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 10.1 | It should load each card independently via separate HTMX requests | Integration | [ ] |
|
|
| 10.2 | It should not prevent other cards from loading when one card endpoint fails | Integration | [ ] |
|
|
| 10.3 | It should display a loading spinner on stub cards until data loads or a timeout occurs | UI | [ ] |
|
|
| 10.4 | It should return appropriate HTTP status codes for card endpoint errors without breaking the page layout | Integration | [ ] |
|
|
|
|
---
|
|
|
|
## Cross-Cutting Behaviors
|
|
|
|
### Permission Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 11.1 | It should allow only admin users to access the dashboard page and card endpoints | Integration | [ ] |
|
|
| 11.2 | It should redirect non-admin authenticated users to /login with a 302 status | Integration | [ ] |
|
|
| 11.3 | It should redirect unauthenticated users to /login with a redirect-to parameter | Integration | [ ] |
|
|
| 11.4 | It should verify admin role via middleware before executing any data queries | Integration | [ ] |
|
|
|
|
### Empty State Behaviors
|
|
|
|
| # | Behavior | Test Strategy | Status |
|
|
|---|----------|---------------|--------|
|
|
| 12.1 | It should render the dashboard page when no clients are selected, with all cards showing empty states | UI | [ ] |
|
|
| 12.2 | It should display an empty bank accounts list when no clients are selected | UI | [ ] |
|
|
| 12.3 | It should display an empty sales chart when no clients are selected | UI | [ ] |
|
|
| 12.4 | It should display an empty expense pie chart when no clients are selected | UI | [ ] |
|
|
| 12.5 | It should show $0.00 income and expenses in the P&L card when no clients are selected | UI | [ ] |
|
|
| 12.6 | It should hide all task sections when no clients are selected | UI | [ ] |
|
|
|
|
---
|
|
|
|
## Test Data Requirements
|
|
|
|
| Entity | Requirements |
|
|
|--------|-------------|
|
|
| **Users** | Admin user with access to multiple clients; non-admin user for permission denial |
|
|
| **Clients** | Minimum 2, ideally 25+; mix with/without bank accounts |
|
|
| **Bank Accounts** | Various types (checking, savings, cash); some linked to Intuit, Yodlee, Plaid; with/without balances and sync timestamps |
|
|
| **Sales Orders** | Orders within and outside the 14-day window with totals |
|
|
| **Invoices** | With expense accounts and unpaid status; voided invoices to test exclusion |
|
|
| **Transactions** | With requires-feedback approval status |
|
|
| **Chart of Accounts** | Categories: sales, COGS, payroll, controllable, fixed overhead, ownership controllable |
|
|
|
|
## Existing Tests to Preserve
|
|
|
|
- No existing dashboard-specific tests have been identified in the current test suite. Any tests covering dashboard routes or card handlers should be preserved during refactoring.
|
|
|
|
## Dependencies
|
|
|
|
- Datomic (primary data store for all card queries)
|
|
- GraphQL/Lacinia (P&L data via get-profit-and-loss-raw)
|
|
- HTMX (progressive card loading via hx-get/hx-trigger/hx-swap)
|
|
- Chart.js (canvas-based charts)
|
|
- Alpine.js (chart data binding)
|