Revert securityProvider to self-pointing; self-heal member applied rights
Two prod issues from the securityProvider-mirror change: 1. Enter-as-System-Member failed with "No membership in the organization's security provider" for e...
Refresh provider status when OAuth popup closes
The provider now redirects to the api-gateway callback (a different origin), so its postMessage may not pass the opener origin check. Re-fetch real provider sta...
Serve e-sign editor PDF for any converted doc, incl native PDFs
The e-sign editor (DocumentEditor → PdfCanvas / PageThumbnailSidebar) opens any converted document, not only files uploaded through the sig-template flow. It fe...
My Docs uses MY_DOCS ordinal (3), not enum id (4)
The backend resolves ImageAssocType via `values()[assocType]` (ordinal index) and persists it @Enumerated(ORDINAL). Every imaging surface passes the ordinal, bu...
Convert deduplicated documents so e-sign edit is enabled
When an uploaded file's bytes matched an existing ImgDat, the dedup path (register-existing) reused that dat verbatim and never ran the conversion pipeline. If ...
Return 200 allFalse for unconfigured org capabilities
GET /api/voip/capabilities threw ProviderNotConfiguredException (422) when an org had no phone provider, logging a red console error on every page load for phon...
Stop 404/422 console errors for un-customized nav and phone-less orgs
Read the ui-preferences collection endpoint (always 200) for the initial navLayout load instead of the single-key GET, which 404s when a member has never custom...
Proactively provision browser-only aliases (media.*)
The log-scan discovery mechanism can never bootstrap the `media` alias: it is only ever contacted by the browser over a WebSocket/XHR subresource (SockJS /ws/in...
Interpret lock LAST_EDIT_AT as UTC for epoch-millis expiry
dbNow() now returns DB-UTC wall-clock (now()::timestamp), so recover the absolute instant with toInstant(UTC) instead of the JVM default zone — keeps the browse...
DbNow() cast now()->::timestamp (TIMESTAMPTZ->Instant broke LocalDateTime)
SELECT now() returns TIMESTAMPTZ, which Hibernate materializes as java.time.Instant and cannot cast to the declared LocalDateTime return type — throwing ClassCa...
Agent filter shows member name + phone extension, not email
The Agent dropdown labelled each teammate with their email because the loader read firstName/lastName keys the backend never sends (it sends nameFirst/nameLast/...
Correct inverted parent-shared topic query
The child-org topic query filtered on assignToOwnOrg=TRUE (own-org-only) when it should return topics SHARED with child orgs (assignToOwnOrg=FALSE). Rename the ...
Send the registrant's hostname in the body so the account lands under the right org
The resolved org was available on the client but never sent to the backend — the org was conveyed only implicitly via X-Forwarded-Host, which the ingress rewrit...
File new accounts under the org of the domain, not kamocrm
/register bound the new member's org to the request Host, but the org signal never survived the hop: kamo-register proxies every signup to the shared api.kamocr...
Resolve org-by-domain with a deepest-label alias fallback
Add **************** exact domain match, then drop the deepest label once (register.optionone.com -> optionone.com) so a per-org register/branding subdomain res...
Stop viewport shaking on browsers with classic scrollbars
On machines whose Chrome uses layout-consuming (non-overlay) scrollbars, the login/recover pages fidgeted with both scrollbars flickering. Root cause: the root ...
Remove "Not available to you" section
Stop surfacing nav features a member lacks access to. The Navigation Layout page listed every hidden nav option as locked chips; dropped the block along with th...
Generic byte endpoints refuse MLOS per-party docs (vault/loan)
The generic imaging byte endpoints (download / stream / bulk-download / thumbnail) and the binder aggregation authorized only on org + a numeric clearance ceili...
Center the vendors-products status snackbar at top
The save/update status pill used MUI's default anchor (bottom-left, no anchorOrigin set) so it rendered off-center. Anchor it top-center.
CreatePair is idempotent for the primary pair (stops duplicate BorrowerPairs)
createPair's sole caller is the wizard's 'ensure primary borrower', but it unconditionally inserted a new pair every call, so a concurrent autosave + explicit S...
Don't serve soft-deleted documents on /stream and /bulk-download
getDocumentMetadata (used by the stream + bulk-download byte paths) does not filter trashed rows the way downloadDocument does, and a soft delete leaves the Min...
Add missing Next.js proxy routes for MLOS default-product + readiness
The vendors-products page threw 'Failed to set default product:' because the frontend PUT to **************** (and GET lead-vendors/mlos-readiness) 404'd — thos...
Raise NavPri z-index above NavTop so the rail overlays the top bar when it expands/peeks
Correct trial pill remaining-time (was 20644d)
When NavPri was rewritten the minute-tick was changed from Date.now() to a counter starting at 0, and that counter was passed as the `now` argument to formatTri...
Reset button in the title row (right) + full-width content
- "Reset to Standard" now sits on the same row as the "Navigation Layout" heading, right-aligned, with the heading left-aligned (moved out of the footer). - T...
PublishRouted so los.pipeline.* events land in LOS_PIPELINE, not rejected
NatsMessageService.publish() pins expectedStream=CHAT_MESSAGES; a los.pipeline.* subject is owned only by the LOS_PIPELINE stream, so the server rejected every ...
Scope borrower's loan document-requirements to their own party
The enriched /document-requirements read authorized any party to the app and returned EVERY party's requirements, so on a joint loan a borrower saw the co-borro...
Per-party vault authorization + per-party notification routing
The account vault held documents per-PARTY (shared human) but authorized access per-ACCOUNT — two HIGH multi-human defects on a joint loan: - PII leak / lockou...
Responsive trial pill + tighten remaining oversized hero headers
- NavPri trial pill: when the rail is expanded it becomes a full-width pill with the fully-qualified label centered ("Trial — 4d 7h 9m left"); collapsed it st...
Gate intake @Component beans behind mlos.intake.enabled (opt-in)
BorrowerScenarioProfileService and ProductDiscoveryGate are shared-lib @Component/@Service beans that inject **************** / mlos.config repos. With blanket ...
Tighten oversized vertical padding on page title headers
The gradient page-title headers had far more top/bottom padding than the horizontal inset where the title text starts, wasting vertical space. Bring the vertica...
Use the lightning-bolt icon for Leads to match the /leads UI
The Leads option used AccountTreeIcon; the /leads "Leads Available" actions use BoltIcon (@mui/icons-material/Bolt). Switch the registry's Leads icon to Bolt so...
De-slop remaining Quick Tips content + make leads tips collapsible
- security, operations, account, and CRM settings help columns: removed all emoji (💡 🚫 ⏳ ✅ 🌍) and rainbow-coloured bullets; every list marker is now one ...
Pipeline per-transaction grouping was broken
TransactionSummaryDTO.loanUids carried LOAN-FILE uids, but the pipeline console keys rows on the APPLICATION uid — so grouping silently fell back to one row per...
**************** (the doc-requirement key)
Surfaces the backing LoanFile.uid so the pipeline can map an app row to its document requirements.
Settings topics are expand-only, not links
Settings topics (Essential Setup, CRM, Security, …) are group headers with no page of their own — only their sub-topics are real destinations. Drop the topics' ...
Member-vault upload was broken (access_level NOT-NULL)
The account-level imaging path had never actually run (0 vault Imgs in prod): uploadDocument was passed accessLevel=null. Pass CONFIDENTIAL for borrower PII (ID...
Stop party fragmentation — enrich the stamped party in place
Live E2E showed a single loan producing 4 parties for 2 humans (an empty placeholder was created at borrower-create before identity, then a 2nd party at identit...
Clean rail alignment, uniform top-bar tiles, and replace Settings slide-out with a sub-option menu
- NavPri logo: the 56px tile made the top of the rail wider than the 44/48px options below it, and collapsed options rendered left-aligned. The logo now sha...
Mlos requirement single-live index keyed per-human (borrower_uid)
Drop the party-only **************** (it would reject a legitimate 2nd co-borrower requirement); create **************** on **************** Already applied to ...
Satisfy-across confused-deputy IDOR + account party self-heal
- HIGH: satisfy-across gated on the path partyId but fanned out over the DOCUMENT's own party downstream; verify the document belongs to the authorized party ...
Party-link cross-human leak + account-level backfill
Adversarial-review fixes: - HIGH: drop the memberId dedup that conflated the loan's isPrimary borrower with the account OWNER — a member self-creating a loan ...
Self-heal party links before enriched requirement read
listDocumentRequirements calls ensurePartyLinks so requirement rows always carry an accountBorrowerPartyId (the borrower upload/satisfy target).
Vendors-products — white-label default-product terminology, dialog option, FFA header
- Rename 'KamoMLOS' → 'Borrower Origination Web Portal' everywhere in the vendors-products UI (star tooltip, snackbars) — this is a white-label multitenant pr...
Default-product set failed — HQL bulk UPDATE disallows the vendor→org join
setDefault used a bulk 'update LeadVendorProduct ... where p.vendor.id in (subquery)' — Hibernate bulk updates reject the implicit association join, so the call...
CreateBlank must persist the app graph before bootstrapBorrower
bootstrapBorrower seeds a Declarations/HMDA shell whose NOT-NULL borrower FK requires the Borrower to be persistent; createBlank called it BEFORE the cascading ...
Borrower self-create = createBlank then stampOwnershipAndGet (two txs)
Sequence the borrower ownership stamp as a separate service call after createBlank commits, so the new borrower/declarations graph is flushed before the account...
Stamp borrower ownership in a separate tx (avoid transient-graph cascade)
createBlankOwnedByMember re-saved the app graph in the same tx as createBlank, before the borrower/declarations rows were flushed → TransientPropertyValueExcept...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.