Job type attributes now support a "Customer Type" pseudo-type: selecting
a customer type expands its attribute definitions inline as real rows,
letting job types reuse field configurations without manual re-entry.
The "customer" placeholder type is stripped server-side before persisting.
Also update production Keycloak redirect URIs from IP to hostname and
ignore .claude/ and .abacusai/ tool directories.
Mirrors the Campaign/CampaignType pattern: Customer has a customer_type_id
plus a JSON attribute_values blob, with the same attribute builder used by
Job Types (text/number/date/boolean/api_lookup with alias and auto-fill).
- Migrations: customer_type, customer_type_audit, customer, customer_audit
(SQL Server, audit tables use I/U/D/R action codes)
- Models, ViewModels, and Repositories for Customer and CustomerType
- CustomerController and CustomerTypeController with full CRUD and audit
logging on insert, update, and delete
- Views for index/create/edit on both entities, using the existing
attribute builder, skeleton loaders, and sticky save bar patterns
- Routes registered under /customers and /customer-types
- Navigation: new fourth group (Customers, Customer Types) with icons
and a separator after Jobs/Job Types
- Dashboard: two new stat cards plus a second row of panels for
Recent Customers and Customers by Type
- JS: customerTypeTable, customerTypeForm, customerTable, customerForm,
and delete helpers added to public/js/app.js