Transaction-first pipeline — PrimeReact expandable rows
Replaces the flat loan grid with a PrimeReact DataTable of TRANSACTIONS that start collapsed and expand IN PLACE to their member loans (no two-click drawer), so...
Re-add the trial pill top-right (color-swapped NavPri pill)
Keeps the trial line in the masthead status strip and re-adds a prominent pill in the top-right so an org's trial mode stays obvious. It's the NavPri expanded t...
Live "insert between" while dragging, not just drop-to-swap
Previously the order only changed on drop, so it read as swapping into a slot. Now the list re-flows live as you drag: dnd-kit onDragOver moves the dragged opti...
Sibling-loan switcher on the application view
A transaction can group multiple loans; the app header now shows a switcher to jump between the deal's sibling loans (hidden for single-loan deals) instead of o...
LoanFileDTO.loanTransactionId (app view knows its deal)
Surfaces the loan's transaction so the /applications view can show/switch sibling loans. Verified: mvn install clean.
**************** (FE type)
Mirrors the backend field for the pipeline Transaction # column. Verified: tsc --noEmit clean.
Surface transactionNumber on TransactionSummaryDTO (pipeline Transaction #)
The per-transaction pipeline row now carries the human transaction number. Verified: mvn compile clean.
Stop external-images banner flashing on already-allowed messages
The reading pane renders a message from its IndexedDB cache before the network fetch returns, and the cached copy lacks the server remoteImagesAllowed flag (und...
Originator projection resolves the per-state license
Completes the live originator projection: the assigned LO's StewardLicense (NMLS_MLO) for the SUBJECT PROPERTY's state (from property.address.subdivision, norma...
Drag-and-drop to rearrange launchpad options, saved per member
Members can now reorder their home options by dragging, and the arrangement is persisted server-side per member (survives reloads and follows them across device...
Make Materials the first tab + default landing; remove Overview
Overview tab removed; Materials is now first. The /marketing index redirects to the first accessible tab (Materials by default), so anyone opening Marketing lan...
Folder create/rename 500 on root folders (Map.of null value)
createFolder/renameFolder built the response with Map.of(..."parentId", parentId), which throws NullPointerException when parentId is null (a root folder) — the...
Live originator projection — org + assigned LO, on read
GET /mortgage-apps/{uid} now overlays a LIVE, system-managed originator projection (computed on read, never stored) unless the row is frozen: org name/NMLS/addr...
Loan Originator section is read-only / system-managed
The Loan Originator card no longer hand-edits URLA §9 data (the duplication of **************** it was re-capturing). It renders read-only: a LIVE projection of...
Transaction-level loan-officer assignment + transaction number
ensureTransactionForApp now stamps an org-unique transactionNumber (TXN-<uid>). New **************** + PUT /mortgage-apps/transactions/ {uid}/loan-officer sets ...
Masonry layout so mixed-height option cards pack without ragged gaps
Leaf cards are short and parent cards vary with their sub-item count (Calculator has 9 modes, VoIP 2), so a uniform grid left big gaps under the short cards in ...
Originator/transaction-first columns (@Order 90)
Additive nullable columns + org-unique transaction-number index for the MLOS originator/transaction refactor: mlos_loan_transaction (transaction_number + assign...
Originator/transaction-first schema — LO assignment, WORM freeze, deal-scoped docs
Backbone for the system-managed-originator + transaction-first refactor (spec 2026-07-08): - LoanTransaction: transactionNumber (org-unique) + assignedLoanOffic...
Add missing account-assign proxy route
The lead-account assign/unassign UI called POST/DELETE **************** but the Next.js proxy route was never created — so requests 404'd and surfaced as "Unkno...
Add Product filter dependent on Vendor
Adds a Product filter to the /leads filter bar, immediately right of the Vendor filter. It behaves like the Status/SubStatus pair: disabled until a vendor is se...
Shared AusEngineClassifier — one source of truth for the §8.2 agency mapping
The program→engine, run→engine, and decision→gate mappings were local to **************** The capital-markets lock-stage AUS hard-stop needs the identical class...
Robust vision provider/model selection across vendors
Two-pass selectVisionProvider: prefer any org provider that has an active vision-capable model adapter already emits image_url content and reports supportsVisio...
AI auto-tag + caption UI; provider cost-tier/vision settings (P3)
Settings → AI → Providers: each provider gains a Cost tier (Light/Medium/Heavy) select and a Supports vision toggle (+ list chips). Materials drawer: 'Suggest t...
Provider cost-tier/vision passthrough + internal one-shot vision endpoint
AiProviderController reads/echoes costTier + supportsVision. ProviderRoutingService gains selectVisionProvider(orgId, tier). **************** runs a one-shot vi...
AI auto-tag + caption via org's providers (P3)
MaterialAiController POST **************** verifies ownership, mints a short-lived signed material URL, and calls AIService's internal vision endpoint (org's ow...
AiProvider cost tier + vision flag (two orthogonal capability axes)
Adds costTier (LIGHT/MEDIUM/HEAVY via new AiProviderTier enum) and supportsVision boolean to AiProvider, so integrations can pick how expensive a provider to us...
Persist "display external images" server-side instead of localStorage
The choice now comes from the message's server-recorded remoteImagesAllowed flag and is saved via POST **************** so it's durable and consistent across de...
Server-side "display external images" consent
Replaces the client-local (localStorage) remembering of the external-image choice with a durable per-member record. New RemoteImageConsentService (fail-soft rea...
EmailRemoteImageConsent entity + repository
Member-scoped record that a member has chosen to display external (remote) images for a specific message, keyed by member_id + normalized RFC Message-ID (unique...
Add INVESTOR_PRICE column to rate_locks + loan_pricing_snapshots
@Order(80) idempotent ADD COLUMN IF NOT EXISTS (DECIMAL(9,4), matching the price-to-100 grids) so the MLOS RCE can record the true non-par investor execution pr...
Record the true non-par investor price on RateLock + LoanPricingSnapshot
The binding rate-lock-of-record and its bound quote carried only rate + lockDays; discount/origination points were left null, so the core entities read PAR whil...
Parent options expose their sub-items instead of being single links
Mail, Docs, VoIP, Calculator and Support are nav options that open a sub-menu rather than navigating, so on the home launchpad they must not be a single link. E...
Persist OAuth provider selection immediately so the switch sticks
Selecting Microsoft 365 / Google Workspace / Zoho only navigated to the connect screen without saving, so leaving before completing OAuth reverted to the previo...
Scope KamoMail mailbox/domain listing to the org's own domains (cross-tenant leak)
SECURITY: **************** ran 'SELECT email FROM virtual_users' (and **************** 'SELECT name FROM virtual_domains') with no org scoping, so mailbox/domai...
Let admins connect RingCentral on a member's behalf
On another member's phone settings, an admin with manage-VOIP rights (canManageVoipConfig) now sees Connect/Reconnect/Disconnect for the member's RingCentral ac...
Allow admins to connect RingCentral on a member's behalf
The per-member RingCentral flow was self-serve only, so an admin managing another member's profile saw "they must connect it themselves". Sysadmins commonly cre...
Remember "display external images" per message
The unblock choice lived in the renderer's local state, but switching messages unmounts/remounts the iframe renderer (the reading pane shows a loader between me...
Usage analytics + Insights view (P2)
Records **************** events and an Insights dialog with org totals + the most-used materials (by downloads + previews).
MaterialAnalyticsController — record events + aggregates
POST **************** (record) + GET /analytics (per-material counts by type + org totals).
MaterialEvent entity+repo (usage analytics)
Append-only usage events **************** with a per-(imgId,type) aggregate query. Table MATERIAL_EVENTS (targeted CRDB DDL; KI auto-scans).
Approval workflow UI + load-all filtering (P2)
Status control in the drawer **************** status badge on tiles, and a status filter in the toolbar. Also loads all material pages up-front (capped) so sear...
MaterialReviewController — status map + set-status
GET /api/media/materials/reviews (org-wide imgId→status map) + POST to set a material's status (validated, reviewer-stamped, upsert).
MaterialReview entity+repo (approval status side-table)
DRAFT/PENDING/APPROVED/ARCHIVED per material, keyed by imgId (imaging schema untouched). Table MATERIAL_REVIEWS (targeted CRDB DDL; KI auto-scans).
Treat ACTIVE status as connected in OAuth provider configs
The Microsoft 365 / Google Workspace / Zoho config views gated their connected state on providerStatus === 'CONNECTED', but the backend EmailProviderStatus enum...
Persist selected OAuth provider on callback so it stops reverting to KamoMail
Switching an org to Microsoft 365 (or Google Workspace / Zoho) never stuck: the OAuth callback stored tokens and only flipped status on a pre-existing provider ...
Per-member RingCentral connect + softphone web-phone v2 fixes
Softphone SDK fixes (ringcentral-web-phone is v2.4.0, not the v0.x the adapter targeted — the old wp.userAgent.* usage threw on init): - Rewrite RingCentralPhon...
Per-member RingCentral OAuth identity + softphone SIP fixes
Softphone SIP credential fixes: - getSipCredentials: map outboundProxyBackup + stunServers (web-phone v2 needs them for WSS failover + ICE/media); throw Provi...
Add MemberVoipOAuthToken for per-member RingCentral connections
Per-member OAuth token keyed (memberId, provider, instanceId) backing extension-scoped RingCentral operations — softphone sip-provision plus the member's person...
Collections/campaigns UI (P2)
Left-nav Collections section (create/select/delete), campaign filter on the collection view, and a collections editor in the detail drawer (add/remove material,...
MaterialCampaignController — CRUD + item map + add/remove
/api/media/materials/campaigns: list/create/update/delete, GET /items (org-wide imgId↔campaignId map), POST /add + /remove with org-ownership checks.
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.