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.
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...
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 ...
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 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...
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...
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...
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...
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).
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.
MaterialCampaign + item entities/repos (collections)
First-class named collections grouping materials across folders. Tables MATERIAL_CAMPAIGNS + MATERIAL_CAMPAIGN_ITEMS (targeted CRDB DDL; KI auto-scans on next r...
Tags UI + access-level control (P2)
Tags (org-scoped, cross-cutting): tag chips on tiles, a tag filter bar (AND across selected), and a tag editor in the detail drawer (assign/remove existing, cre...
MaterialTagController — tag CRUD + assign/unassign + assignment map
/api/media/materials/tags: list/create/delete tags, GET /assignments (org-wide imgId↔tagId map the workspace joins client-side), POST /assign + /unassign with o...
MaterialTag + assignment entities/repos (org-scoped tags)
Flat, cross-cutting tag axis over folders for marketing materials. Tables MATERIAL_TAGS and MATERIAL_TAG_ASSIGNMENTS (created via targeted CRDB DDL; KI auto-sca...
Managed public links UI (P1) — create/expiry/revoke/view-count
Detail drawer gains a 'Public links' panel (ShareLinkManager): create a durable link with an optional label and expiry (1h/1d/7d/30d/never), copy it, see its vi...
Managed public-link endpoints (create/list/revoke) + tracked serve
Adds POST/GET /api/media/materials/links and DELETE /links/{id} backed by MaterialShareLink, and resolves managed tokens on the public GET first (checking revok...
MaterialShareLink registry entity + repo (managed/tracked public links)
Backs revocable, expiring, view-counted public links for marketing materials — persisted so links can be listed, revoked, and counted (vs. the stateless HMAC on...
Add right-click / long-press context menu to conversation-view rows
Completes the list action menu across both view modes. Conversation rows now open the same shared menu on right-click and touch long-press with thread-level act...
DecisionGate.appliedThreshold exposes the actual confidence bar
The gate internally applies max(tenant override, safetyFloor, stage floor) but callers only had the pre-gate tenant wall. appliedThreshold returns the true bar ...
Enterprise Materials workspace (P0) — folders, search, bulk, real preview, shared email composer
Replaces the flat 200-item grid with a full document workspace over the existing imaging backend (which already supports folders, trash, sharing, history, bulk ...
Overhaul /messages — iframe rendering, list context menu, threading, races, a11y
Implements the audit of the /messages page end-to-end. Reported issues: - Reply/Reply All/Forward buttons now show text labels; removed from the more-actions ...
Instrument Panel redesign — accent families, masthead, section-index nav, unified glass card
Redesigns the two most-visited landings into a permission-shaped operator's console. Foundation - Turn on the already-bundled Geist Sans/Mono (were discarded b...
**************** targeted update
Async conversion (virtual threads) and scheduled sweeps hold a detached ImgDat; save()/merge() cascades into the orphanRemoval=true images collection and throws...
Add Reply All to the messages reading pane and thread view
Reply All was advertised (keyboard-shortcut label + i18n key) but had no handler. Wire it up: new computeReplyAllRecipients helper puts the sender in To and eve...
Partial-unique index enforcing one active closing package per loan (eClose double-close backstop)
CREATE UNIQUE INDEX uk_mlos_closing_pkg_active_loan ON mlos_closing_package (loan_file_uid) WHERE status <> 'CANCELLED'. Durable backstop behind the assembler's...
Thumbnail scheduled-generated materials in-process
A headless sweep can't drive ConversionService's OTK thumbnail pipeline, so generate a page-0 PNG thumbnail via ImageIO right after storing the export — schedul...
Like what you see shipping?
All of it arrives in your workspace on its own. Start on the free plan and read this page again in a month.
