# Admin Behaviors ## Overview The Admin section is a server-side rendered (SSR) HTMX interface for superuser operations in Integreat. All admin pages require the `admin` user role. Non-admin users are redirected away. The admin area includes dashboards, entity management grids, background job orchestration, audit history, and bulk import tools. ## Routes & Pages | Page | Route | Handler Namespace | |------|-------|-------------------| | Admin Dashboard | `/admin` | `auto-ap.ssr.admin` | | Clients | `/admin/clients` | `auto-ap.ssr.admin.clients` | | Accounts | `/admin/accounts` | `auto-ap.ssr.admin.accounts` | | Vendors | `/admin/vendors` | `auto-ap.ssr.admin.vendors` | | Transaction Rules | `/admin/transaction-rules` | `auto-ap.ssr.admin.transaction-rules` | | Background Jobs | `/admin/jobs` | `auto-ap.ssr.admin.background-jobs` | | History / Audit | `/admin/history` | `auto-ap.ssr.admin.history` | | Import Batches | `/admin/import-batches` | `auto-ap.ssr.admin.import-batch` | | Excel Invoices | `/admin/excel-invoices` | `auto-ap.ssr.admin.excel-invoice` | | Sales Summaries | `/admin/sales-summaries` | `auto-ap.ssr.admin.sales-summaries` | All routes are wrapped with `wrap-client-redirect-unauthenticated` followed by `wrap-admin`. ## Behaviors by Page ### Admin Dashboard **Display** - Shows two Chartist charts: - **Growth in clients**: Bar chart showing client count at 2 years ago, 1 year ago, and today (uses `dc/as-of` against Datomic history). - **Changes by hour**: Line chart showing Datomic transaction counts per hour over the last 24 hours. - Uses the standard admin page layout with `admin-aside-nav`. **Access Control** - Only accessible to users with admin role. - Unauthenticated users are redirected to login. ### Client Management **Grid Display** - Columns: Name, Code, Locations (as pills), Emails (as pills), Status. - Status column shows: - Lock status: "Locked " with color coding (green < 90 days, yellow < 365 days, red otherwise). - "Not locked" in red if no lock date. - Bank account integration status pills (red for failed/unauthorized). - Row actions: Biweekly Sales PowerQuery button, Edit button (pencil icon). - Global action: "New Client" button opens wizard. **Filtering** - Name (case-insensitive substring match). - Code (exact match, upper-cased). - Group (exact match on client groups, upper-cased). - Select filter: "All" or "Only mine" (filters to clients assigned to current user). - Filters trigger HTMX request with 500ms debounce on change, 1000ms on keyup. **Sorting** - By name, code. - Pagination: 25 per page default. **Client Wizard (Create / Edit)** - Multi-step linear wizard with steps: Info → Matches → Contact → Bank Accounts → Integrations → Cash Flow → Other Settings. - **Info step**: Name (required), Code (immutable on edit), Locked Until date, Locations (dynamic grid). - **Matches step**: String match patterns, location match patterns (match → location mapping). - **Contact step**: Address (street1, street2, city, state, zip), Email contacts grid (description + email). - **Bank Accounts step**: Sortable card list of existing accounts. Add new cash/credit/checking accounts. Each account has type-specific form. - Cash account: nickname, code, financial code (numeric), start date, include-in-reports, visible-for-payment. - Credit card: same + bank name, account number, Plaid/Yodlee/Intuit integration selectors. - Checking: same + routing number, bank code, check number. - Validation: financial code is required if "Include in Reports" is true. - **Integrations step**: Square auth token input, refresh Square locations button, Square location → client location mapping grid. - **Cash Flow step**: Week A/B credits and debits (4 numeric fields). - **Other Settings step**: Feature flags (dropdown with known flags), Groups (free text grid). **Save Behavior** - POST for create, PUT for update. - Code uniqueness validation on create. - Groups are upper-cased on save. - Bank account start dates coerced to dates. - After save: row flashes in grid, modal closes, Solr reindexes client. **Biweekly Sales PowerQuery** - Generates 6 saved queries per client (sales summary, category, expected deposits, tenders, refunds, cash drawer shifts). - Opens modal with copy-to-clipboard buttons for Excel Power Query M-code. ### Account Management **Grid Display** - Columns: Code (numeric), Name, Type (pill), Location. - Row action: Edit button. - Global action: "New Account" button. **Filtering** - Name (case-insensitive substring on upper-cased name). - Code (exact numeric match). - Type: All, Dividend, Asset, Equity, Liability, Expense, Revenue, None. **Sorting** - By code, name, type, location. - Default sort by upper-cased numeric code. **Account Dialog (Create / Edit)** - Modal card with live-updating header showing code and name. - Fields: - Numeric Code (required, unique on create; hidden on edit). - Name (required). - Account Type (required, enum: asset, liability, equity, revenue, expense, dividend, none). - Location (optional string). - Invoice Allowance (enum: allowed, denied, warn). - Vendor Allowance (enum: allowed, denied, warn). - Applicability (enum: global, customized). - Client Overrides grid: client typeahead + override name. Validates no duplicate clients. **Save Behavior** - POST for create, PUT for update. - Numeric code uniqueness check on create. - Client override uniqueness validation. - After save: Solr reindexes account + all client overrides. ### Vendor Management **Grid Display** - Columns: Name (with usage pills), Email, Default Account. - Usage pills: "Unused" (red) if 0 clients, "Used by N clients" (primary), "Used N times" (secondary). - Row action: Edit button (opens wizard). - Global actions: "Merge" button, "New Vendor" button. **Filtering** - Name (case-insensitive substring on upper-cased name). - Type: All, Only hidden, Only global. **Vendor Wizard (Create / Edit)** - Timeline steps: Info → Terms → Account → Address → Legal. - **Info step**: Name (required, 3+ chars), Print As (optional, toggleable), Hidden (admin-only checkbox). - **Terms step**: Terms in days (integer), Terms Overrides grid (client + days), Automatically Paid When Due grid (client list). - **Account step**: Default Account (typeahead), Account Overrides grid (client + account typeahead). Account typeahead is scoped by selected client. - **Address step**: Street1, Street2, City, State (2 chars), Zip (5 chars). - **Legal step**: Legal Entity Name OR First/Middle/Last name, TIN, TIN Type (EIN/SSN), 1099 Type (enum). **Vendor Merge** - Modal with Source Vendor (to be deleted) and Target Vendor. - Validation: source and target must differ. - On merge: all references to source vendor are retracted and asserted as target vendor. Source vendor entity is retracted. - Shows success notification after merge. **Save Behavior** - POST for create, PUT for update. - Solr reindexes vendor name + hidden flag. ### Transaction Rules **Grid Display** - Columns: Client (or group pill), Bank Account, Description, Amount (gte/lte pills), Note. - Row actions: Delete (with confirmation), Execute (play icon), Edit (pencil icon). - Global action: "New Transaction Rule" button. **Filtering** - Vendor (entity typeahead). - Note (case-insensitive regex match). - Description (case-insensitive substring). - Client Group (exact upper-cased match). **Transaction Rule Wizard** - Two-step wizard: Edit → Test. - **Edit step**: - Description (required, regex pattern, 3+ chars). - Optional togglable filters: Client, Client Group, Bank Account, Amount range (gte/lte), Day of Month range (gte/lte). - Bank account selector is scoped by selected client. - Outcomes: Assign Vendor (typeahead), Accounts grid (account + location + percentage), Approval Status (radio: unapproved/approved). - Account location is derived from account's fixed location, client locations, or "Shared". - Validation: account percentages must sum to 100%, bank account must belong to selected client, location must match account's fixed location if set. - **Test step**: Shows matching transactions (up to 15) with client, bank, date, description. Badge shows total count ("99+" if ≥99). **Execute** - Opens dialog with checkbox-selectable transactions that match the rule AND are unapproved. - Only transactions on or after client's `locked-until` date are included. - Can select "All" or individual transactions. - On execution: applies rule coding to each transaction via `upsert-transaction`, touches Solr index. - Shows notification: "Successfully coded X of Y transactions!" **Delete** - Confirms before delete. - Retracts entity from Datomic. - Row fades out with "live-removed" class. ### Background Jobs **Grid Display** - Columns: Start time, End time, Duration (minutes), Name, Status. - Status values: `:running`, `:pending`, `:succeeded`, `:failed`. - Data source: ECS tasks filtered by `INTEGREAT_JOB` environment variable. - Global action: "Run job" button. **Job Start Dialog** - Job type dropdown: Yodlee Import, Yodlee Account Import, Intuit Import, Plaid Import, Bulk Journal Import, Square Import, Register Invoice Import, Upsert recent ezcater orders, Load Historical Square Sales, Export Backup. - Dynamic subform based on job type: - Bulk Journal Import: S3 URL path input. - Register Invoice Import: S3 URL path input. - Load Historical Sales: Client typeahead + Days (1-120). - Validation: cannot start a job that is already running. - On submit: runs ECS Fargate Spot task with selected task definition. ### History / Audit **Display** - Search box for entity ID (numeric Datomic entity ID). - History table shows: Date, User, Field, From value, To value. - Values are formatted: dates → local format, large integers (>1M) → clickable links to that entity's history, nil → "(none)", others → pr-str. - Entity ID links load that entity's history inline. - Snapshot link opens inspector showing full entity pull `[*]`. - No pagination (all history rows shown). **Inspector** - Card showing all attributes of an entity at current database value. - Clickable entity IDs recurse into history. ### Import Batches **Grid Display** - Columns: Date, Source, Status, User, Imported, Pre-existing, Suppressed. - Row action: External link to transactions filtered by import batch. **Filtering** - Date range (start/end). - Source (enum: import-source values). **Sorting** - By date, source, status, user. ### Excel Invoices **Display** - Single-page form with large textarea for tab-separated invoice data. - Shows sample data as placeholder. **Import Behavior** - Parses tab-separated rows with columns: raw-date, vendor-name, check, location, invoice-number, amount, client-name, bill-entered, bill-rejected, added-on, exported-on, account-numeric-code. - Validates and resolves: client by code or name, vendor by name, account by numeric code. - Groups rows into: new, existing (by vendor+client+invoice-number), errors. - For new rows: creates invoice, optionally payment (if "Cash" check), and cash transaction. - Cash invoices get status "paid" with zero outstanding balance. - Non-cash invoices get status "unpaid" with full outstanding balance. - Results shown as pills: imported count, extant count, vendors not found (hover tooltip), error grid. ### Sales Summaries **Grid Display** - Columns: Client (hidden if only one client), Date, Debits (itemized list), Credits (itemized list). - Each item shows category, amount, and "missing account" pill in red if no account mapped. - Total row shows "Total: $X" with green pill if balanced, red if unbalanced. - Row action: Edit button. **Filtering** - Date range (start/end). - Scoped to user's valid clients. **Edit Wizard** - Shows all sales summary items in a grid: Category, Account, Debits, Credits. - Manual items: editable category, account typeahead, debit/credit inputs, removable. - Auto items: read-only category and amount, editable account. - Account typeahead is scoped by client and filtered for invoice-purpose accounts. - Live total row and unbalanced row update on amount changes. - Validation: each item must have exactly one of credit or debit, not both. - Validation: debits must equal credits (balanced). - Save updates ledger-mapped account assignments. Manual items get `manual?` flag and ledger-side/amount attached. ## Cross-Cutting Behaviors ### Admin-only Access - All admin routes use `wrap-admin` middleware. - Non-admin authenticated users receive an authorization failure (typically redirect or error). - Unauthenticated users are redirected to login via `wrap-client-redirect-unauthenticated`. ### Impersonation - Admin users can select a client from the global client selector. - Some admin grids (clients, transaction rules, sales summaries) respect the selected client and filter results accordingly. ### History Tracking - All mutating admin operations use `audit-transact` or `audit-transact-batch`. - Transactions record `:audit/user` attribute. - The History page queries Datomic's history database (`dc/history`) to show all changes to an entity. ### Permissions - Admin role is required for all admin handlers. - No finer-grained permissions within admin area. ### Form Validation Patterns - Malli schemas enforce form structure. - `wrap-schema-enforce` validates query params, route params, and form params. - `wrap-form-4xx-2` re-renders dialogs with validation errors on 400 responses. - HTMX response targets (`#form-errors .error-content`) display field-level errors. ### Solr Indexing - After create/update of clients, accounts, and vendors, Solr documents are reindexed. - This affects search typeaheads across the application. ## Edge Cases **Client Management** - Client code must be unique on create; immutable on edit. - Bank account code is immutable after creation. - Financial code (numeric) required when "Include in Reports" is true. - Square location refresh times out after 2 seconds → shows "No locations found." - Bank accounts are sortable via drag-and-drop (sortable.js integration via `hx-trigger="end"`). **Account Management** - Numeric code must be unique on create. - A client can only have one override per account. - Applicability and allowances are enums with specific values. **Vendor Management** - Vendor merge fails if source equals target. - Account override typeahead depends on client selection; changing client updates available accounts. - Terms override requires unique clients (no duplicate client overrides). **Transaction Rules** - Rule execution only affects unapproved transactions. - Transactions before client's `locked-until` date are excluded from execution. - Account percentages must sum to exactly 100%. - If account has a fixed location, the rule location must match. **Background Jobs** - Cannot start a job that is already running (based on ECS task status). - ECS API failures propagate as exceptions. **Excel Invoices** - Vendor name resolution is case-sensitive exact match. - Location format expected: `CLIENTCODE-LOCATION`. - Missing client code or location adds error row. - Cash check type creates paid invoice with transaction; others create unpaid invoice. **Sales Summaries** - Debits and credits must balance to save. - Manual items require both category and amount. - Account typeahead is scoped to client + invoice-purpose accounts. **History** - Entity ID must be parseable as a Long; otherwise shows error notification. - Very old entities may have no history if created before audit attributes. ## Test Data Requirements ### Users - Admin user with `:user/role :user-role/admin`. - Non-admin user with `:user/role :user-role/user` for access control tests. ### Clients - Client with `:client/name`, `:client/code` (unique), `:client/locations`. - Client with `:client/locked-until` in the past and future. - Client with bank accounts (cash, credit, checking types). - Client with Square auth token for integration tests. - Client with feature flags and groups. ### Accounts - Account with `:account/numeric-code` (unique), `:account/name`, `:account/type`. - Account with `:account/location` fixed. - Account with client overrides. ### Vendors - Vendor with `:vendor/name`, `:vendor/default-account`. - Vendor with terms overrides and account overrides. - Hidden and non-hidden vendors. - Vendor with 1099 legal entity info. ### Transaction Rules - Rule with description pattern, client, bank account, amount gte/lte. - Rule with account assignments summing to 100%. - Unapproved transactions matching rule criteria. - Transactions before and after client's locked-until date. ### Background Jobs - ECS cluster with task definitions containing `INTEGREAT_JOB` env var. - Or mock ECS responses for unit tests. ### Import Batches - Import batch entities with `:import-batch/date`, `:import-batch/source`, `:import-batch/status`. ### Sales Summaries - Sales summary with items having `:ledger-mapped/ledger-side` and `:ledger-mapped/amount`. - Both manual and auto-generated items. ## Dependencies - Datomic (history, transactions, pull API) - HTMX (frontend interactivity) - Alpine.js (modal state, conditional visibility) - Chartist (dashboard charts) - Solr (search indexing) - ECS API (background jobs) - Malli (schema validation) - Bidi (routing) ## Related Test Files - `test/clj/auto_ap/integration/graphql/users.clj` - User role and permission tests - `test/clj/auto_ap/integration/graphql/accounts.clj` - Account search and override tests - `test/clj/auto_ap/integration/graphql/vendors.clj` - Vendor management tests - `test/clj/auto_ap/integration/graphql/transaction_rules.clj` - Rule matching and execution tests