Events & Workflows
What happens behind the scenes when a loan moves through its lifecycle — the events fired, who listens, and what gets triggered.
This page is the product-team view of the portal's automation: when X happens, what does the system do automatically, and why? It is written in cause→effect terms. For the code-level details, engineers should read Engineering → Event-Driven Architecture.
When a loan's status changes
The portal's central automation hook is a loan status change. When a loan
moves from one lifecycle status to another (and that change is saved), the system
fires a single event — LoanStatusChanged — that records:
- the loan,
- the status it moved from,
- the status it moved to, and
- the actor (the user who made the change).
Two things listen for that event, and they are kept separate on purpose:
| Listener | What it does |
|---|---|
| Notifications | Sends the status-change notifications (its own dedicated path). |
| Workflow engine | Runs every other automation configured for that transition. |
The workflow engine evaluates configured workflows against the change (e.g. "loan moved to Underwriting") and runs their actions — for example, creating the standard set of underwriting conditions.
When an underwriter signs off a condition
This is a common question, and the honest answer matters:
Clearing a condition is a direct action, not an event
When an underwriter clears or waives a condition, the system records the resolution directly: the condition's status becomes Cleared or Waived, and it stamps who cleared it and when. Today this does not fire its own event, so there is no automatic downstream workflow triggered purely by a single condition being signed off.
What does drive automation is the loan status moving forward (for example,
once all conditions are satisfied and someone advances the loan). That status
change is what fires LoanStatusChanged and runs the workflow engine.
Condition states
| State | Meaning |
|---|---|
| Pending | Open; awaiting documentation or sign-off. |
| Cleared | Satisfied and signed off by the resolver. |
| Waived | Intentionally not required for this loan. |
Product implication
If the business wants "underwriter signs off the last condition → automatically
advance the loan / notify the borrower," that is a net-new event an engineer
would add (a ConditionResolved domain event). Flagging it here so product can
decide whether to prioritize it. This is exactly the kind of gap this catalog
exists to make visible.
When borrowers e-sign disclosures
Disclosure packages are sent for electronic signature through the disclosure vendor (DocMagic). From there the signing ceremony happens outside the portal, so the portal learns about progress through a webhook: each time the package advances, the vendor calls back and the portal records a disclosure event against the loan.
These events form an append-only timeline of the eSign/eConsent ceremony — for
example PackageCreated → the borrower consents to sign electronically → each
participant signs → PackageCompleted. The loan's Disclosures tab presents
that timeline newest-first and highlights the milestones that mean signing is
finished:
| Completed milestone | Meaning |
|---|---|
| Borrowers Electronically Signed | Every borrower has signed. |
| All Participants Electronically Signed | All required parties have signed. |
| Signing Completed | The signing ceremony finished. |
| Regulatory Delivery Requirements Met | The compliance delivery-timing rules are satisfied. |
| Package Completed | The package is fully complete. |
The raw vendor payload stays server-side
Each webhook carries a full vendor payload that can include borrower PII. The portal keeps it for audit but never sends it to the browser — the timeline shows only the event type, who acted, when, and an optional note.
Because these events arrive asynchronously after the package is sent, the Disclosures tab refreshes itself while it is open so new signing activity appears without a manual reload, and it stops refreshing once a completed milestone is reached.
Product implication
This is loans only. A lead has no LOS loan number before it converts, and the webhook keys every event by that number — so the eSign timeline exists only once a file is a loan.
Why events instead of inline code?
Keeping "what happened" (the event) separate from "what to do about it" (the listeners and workflows) means new automation can be added without touching the code that changes a loan's status — notifications, condition creation, and future integrations all subscribe to the same events.