# LendingDocumentation

This is the editable source document for the Agentic Loan Applications Documentation site.

Edit only the content inside `site:field` blocks. Keep the `DOCS:SECTION` and `site:field` comments in place so the site can be regenerated safely.

Site-managed structure such as section order, groups, related sections, previous/next links, and the index is intentionally not editable here.

<!-- DOCS:SECTION id="getting-started" -->
## Getting Started

<!-- site:meta group="Getting Started" -->

### Summary
<!-- site:field summary -->
After you install the Agentic Loan Applications solution from Forge, complete these configuration steps so the application is up and running.
<!-- /site:field summary -->

### Summary HTML
<!-- site:field summaryHtml -->

<!-- /site:field summaryHtml -->

### Image Reference
<!-- site:field image -->

<!-- /site:field image -->

### Body Text
<!-- site:field bodyText -->

<!-- /site:field bodyText -->

### Key Points
<!-- site:field keyPoints -->

<!-- /site:field keyPoints -->

### Ordered Items
<!-- site:field orderedItems -->

<!-- /site:field orderedItems -->

### HTML Content
<!-- site:field htmlContent -->
<section class="temporary-support-list" aria-label="Getting started after Forge install">
  <h3>1. Open the three main applications</h3>
  <p>The first step after installation is to open the three main applications in the browser. Replace <code>[your-tenant-host]</code> with your tenant hostname. For each application, the login page should be displayed.</p>
  <ul class="key-points">
    <li><strong>Mobile Banking</strong> — <code>[your-tenant-host]/CloneofMobileBanking</code>. The mobile app where customers request a loan application.</li>
    <li><strong>Lending Console</strong> — <code>[your-tenant-host]/CloneofLendingConsole/</code>. The back-office app where the bank's loan officer monitors the process and intervenes when needed.</li>
    <li><strong>Banking Sync Services</strong> — <code>[your-tenant-host]/CloneofBankingSyncServices</code>. The operational app where you can review the current state, reset applications, and create loan offers for users.</li>
  </ul>
  <h3>2. Set the DevelopmentDomain setting</h3>
  <p>From any of the three applications, copy the host from the URL. It should end in <code>.app</code>.</p>
  <p>In ODC Portal, open the <strong>Solutions Common Services</strong> app and edit the <code>DevelopmentDomain</code> setting, replacing its value with the hostname you copied. Wait until the setting takes effect, then refresh each of the three applications.</p>
  <p>Each login page should now show an additional option: a button to sign in as a demo user, with that user's role shown in brackets when a role applies:</p>
  <ul class="key-points">
    <li><strong>Mobile Banking</strong> — Log in as Matthew Sheldon</li>
    <li><strong>Lending Console</strong> — Log in as Eddie Riedel (Officer)</li>
    <li><strong>Banking Sync Services</strong> — Log in as Lydia Miller (Setup Control)</li>
  </ul>
  <p>If a button does not appear, wait a moment and try again — the setting can take a short time to propagate.</p>
  <h3>3. Bootstrap sample data</h3>
  <p>To make the applications more lively, bootstrap some sample data. In ODC Portal, open <strong>Clone of Banking Sync Services</strong> and find the <code>SyncData</code> timer. Running this timer imports the bootstrap data. To reset all data and import it again, use the <code>SyncDataRecreate</code> timer.</p>
  <p>After <code>SyncData</code> has run, confirm the data in each application:</p>
  <ul class="key-points">
    <li><strong>Mobile Banking</strong> — Log in as Matthew Sheldon. He should already have 2 accounts.</li>
    <li><strong>Lending Console</strong> — Log in as Eddie Riedel. He should have 9 tasks.</li>
    <li><strong>Banking Sync Services</strong> — Log in as Lydia Miller. The dashboard should show information about Matthew Sheldon.</li>
  </ul>
  <h3>4. Configure your own AI models (optional)</h3>
  <p>Banking agents ship with the trial default model <code>TrialClaudeHaiku4_5</code>. Before production use, change each agent's model from that default to the recommended model for that agent (see <a href="banking-agents.html">Banking Agents — Model recommendations</a>):</p>
  <ul class="key-points">
    <li><strong>Lending Policy Agent</strong> — change from <code>TrialClaudeHaiku4_5</code> to <strong>Claude Sonnet 4.6</strong>.</li>
    <li><strong>Banking Document Agent</strong> — change from <code>TrialClaudeHaiku4_5</code> to <strong>Claude Opus 4.7</strong>.</li>
    <li><strong>Lending Fraud Agent</strong> — change from <code>TrialClaudeHaiku4_5</code> to <strong>Claude Haiku 4.5</strong>.</li>
  </ul>
  <p>Leaving agents on <code>TrialClaudeHaiku4_5</code> is only for trial or early exploration. For customer-impacting Document workloads in particular, keep the recommended Opus model rather than a cheaper trial default.</p>
  <aside class="next-step-callout" aria-label="Ready to test the application">
    <p class="next-step-callout-label">Next</p>
    <p><strong>If you have completed these steps, you are now able to test the application.</strong></p>
    <p><a href="test-loan-origination-flow.html">Continue to Test Loan Origination Flow</a></p>
  </aside>
</section>
<!-- /site:field htmlContent -->

### Integration Pattern
<!-- site:field integrationPattern -->

<!-- /site:field integrationPattern -->

<!-- /DOCS:SECTION -->

<!-- DOCS:SECTION id="test-loan-origination-flow" -->
## Test Loan Origination Flow

<!-- site:meta group="Getting Started" -->

### Summary
<!-- site:field summary -->
This is a test scenario to see the Agentic Loan Applications solution in action. The use case is a user who accepts a pre-approved loan offer and follows the happy path until they receive the loan. Use the step-by-step guide below.
<!-- /site:field summary -->

### Summary HTML
<!-- site:field summaryHtml -->

<!-- /site:field summaryHtml -->

### Image Reference
<!-- site:field image -->

<!-- /site:field image -->

### Body Text
<!-- site:field bodyText -->

<!-- /site:field bodyText -->

### Key Points
<!-- site:field keyPoints -->

<!-- /site:field keyPoints -->

### Ordered Items
<!-- site:field orderedItems -->

<!-- /site:field orderedItems -->

### HTML Content
<!-- site:field htmlContent -->
<section class="temporary-support-list" aria-label="Test loan origination flow">
  <h3>1. Open Matthew Sheldon's overview</h3>
  <p>Go to <code>[your-tenant-host]/CloneofBankingSyncServices/</code>, log in as Lydia Miller, and on the dashboard click <strong>Go to Overview</strong> in the Matthew Sheldon row.</p>
  <h3>2. Restart the customer with one offer</h3>
  <p>Click <strong>Restart Customer with one Offer</strong> and wait for the message: <strong>Successfully restart the customer with an offer.</strong></p>
  <h3>3. Check the offer details</h3>
  <p>On the page, confirm that Amount / Term / Rate is:</p>
  <ul class="key-points">
    <li>€60,000.00</li>
    <li>48 months</li>
    <li>8,50%</li>
  </ul>
  <aside class="next-step-callout" aria-label="Continue in Mobile Banking">
    <p class="next-step-callout-label">Go to Mobile Banking</p>
    <p>Open <code>[your-tenant-host]/CloneofMobileBanking</code>.</p>
  </aside>
  <h3>4. Review the pre-qualified offer</h3>
  <p>Log in as Matthew Sheldon and confirm that a green card shows the loan offer: <strong>You're pre-qualified for up to $60,000.00 from 8.5% APR.</strong></p>
  <h3>5. Start the application</h3>
  <p>Click <strong>Apply now</strong> on the first card after the <strong>For you</strong> section. The application opens the chat window and welcomes the user with:</p>
  <p><strong>Hi &lt;sample user&gt;! Dreaming of something big? Let's make it happen. You are pre-qualified for a $60,000.00 Personal Loan loan in a 48-month term. Would you like to proceed with your application?</strong></p>
  <h3>6. Confirm you want to proceed</h3>
  <p>Type <strong>Yes</strong> in the chat text box and press the send icon. The agent waiting icon is displayed, then the agent asks:</p>
  <p><strong>Great, we're all set! To move forward, I'll need a few documents from you. Let's start with a government-issued photo ID — could you please upload your driver's license, passport, or national ID?</strong></p>
  <h3>7. Upload a valid driver's license</h3>
  <p>Use this driver's license, <a href="https://solutions-lending-sample-docs.s3.us-east-1.amazonaws.com/drivers_license_matthew_shelton.png">download it</a>, and upload it. The agent waiting icon is displayed, then the agent asks:</p>
  <p><strong>ID accepted! Could you now upload a recent pay stub (last 30 days) as proof of income?</strong></p>
  <h3>8. Upload a valid pay stub</h3>
  <p>Use this pay stub, <a href="https://solutions-lending-sample-docs.s3.us-east-1.amazonaws.com/paystub_matthew_shelton.pdf">download it</a>, and upload it. The agent waiting icon is displayed, then the agent asks:</p>
  <p><strong>Pay stub accepted! Last thing — could you please upload a proof of address (utility bill, bank statement, or lease agreement)?</strong></p>
  <h3>9. Upload a valid proof of address</h3>
  <p>Use this proof of address, <a href="https://solutions-lending-sample-docs.s3.us-east-1.amazonaws.com/matthew_proof_of_address.pdf">download it</a>, and upload it. The agent waiting icon is displayed, then the agent says:</p>
  <p><strong>Doing a final validation on your documents... hang in there!</strong></p>
  <p>After a while, the agent asks:</p>
  <p><strong>All documents are verified! I have everything I need to submit your application. To finalize it, I'll need to run a hard credit check — this will appear on your credit report. Shall I go ahead?</strong></p>
  <h3>10. Confirm the credit check</h3>
  <p>Type <strong>Yes</strong> in the chat text box and press the send icon. A PIN pad is displayed.</p>
  <h3>11. Enter the PIN</h3>
  <p>Enter the code <strong>1234</strong>. The agent waiting icon is displayed, then the agent says:</p>
  <p><strong>Your application has been submitted and is now being analysed — you'll receive any updates right here in this chat.</strong></p>
  <p>A message is then displayed saying: <strong>Analyzing your application</strong>.</p>
  <h3>12. Wait for the analysis to finish</h3>
  <p>Wait on <strong>Analyzing your application</strong>. The loading icon is replaced by a green check, then this message is displayed:</p>
  <p><strong>Thanks for waiting! I'm going to have a someone review your application. We will contact you soon.</strong></p>
  <aside class="next-step-callout" aria-label="Continue in Lending Console">
    <p class="next-step-callout-label">Go to Lending Console</p>
    <p>Open <code>[your-tenant-host]/CloneofLendingConsole</code>.</p>
  </aside>
  <h3>13. Log in as the loan officer</h3>
  <p>Click <strong>Log in as Eddie Riedel (Officer)</strong>. The loan officer sees the dashboard.</p>
  <h3>14. Open Applications</h3>
  <p>Click the <strong>Applications</strong> menu option. The loan officer sees the Applications page and checks that the user's application is in status <strong>Referred</strong>.</p>
  <h3>15. Open the application detail</h3>
  <p>Click the application number link. The loan officer sees the Application detail page.</p>
  <h3>16. Approve the offer options</h3>
  <p>Click <strong>Approve</strong> and fill in the popup text box with a reason to approve the offer options.</p>
  <aside class="next-step-callout" aria-label="Continue in Mobile Banking">
    <p class="next-step-callout-label">Go to Mobile Banking</p>
    <p>Open <code>[your-tenant-host]/CloneofMobileBanking</code>.</p>
  </aside>
  <h3>17. Select option 1</h3>
  <p>The user selects option <strong>1</strong>. The loan agreement page is displayed with the loan details.</p>
  <h3>18. Agree and submit</h3>
  <p>Check <strong>I've read the Terms &amp; Conditions</strong> and click <strong>Agree and Submit</strong>. The success page appears, showing that the loan application was approved.</p>
  <h3>19. Return to the dashboard</h3>
  <p>Click <strong>Done</strong>. The dashboard is displayed, and onboarding should show one loan account with the value <strong>$60,000.00</strong>.</p>
</section>
<!-- /site:field htmlContent -->

### Integration Pattern
<!-- site:field integrationPattern -->

<!-- /site:field integrationPattern -->

<!-- /DOCS:SECTION -->

<!-- DOCS:SECTION id="overview" -->
## Overview

<!-- site:meta group="The Agentic Loan Applications Solution" -->

### Summary
<!-- site:field summary -->
This documentation explains the Agentic Loan Applications solution at a high level: what the platform supports, how the main modules work together, and where each capability fits within the end-to-end banking loan journey.
<!-- /site:field summary -->

### Summary HTML
<!-- site:field summaryHtml -->

<!-- /site:field summaryHtml -->

### Image Reference
<!-- site:field image -->

<!-- /site:field image -->

### Body Text
<!-- site:field bodyText -->

<!-- /site:field bodyText -->

### Key Points
<!-- site:field keyPoints -->
- The solution supports loan origination across customer-facing channels, back-office operations, AI-assisted analysis, workflow orchestration, core banking services, and integration services.
- The document is organized around the major solution areas: workflow, module architecture, user applications, banking agents, core services, integration services, synchronization, audit, and customization.
- Each section describes the role of the relevant modules and the boundaries between user experience, workflow, business services, AI agents, and external integrations.
- Customization guidance highlights where a corporation should adapt APIs, processes, policies, prompts, operating configuration, and future documentation areas.
<!-- /site:field keyPoints -->

### Ordered Items
<!-- site:field orderedItems -->

<!-- /site:field orderedItems -->

### HTML Content
<!-- site:field htmlContent -->

<!-- /site:field htmlContent -->

### Integration Pattern
<!-- site:field integrationPattern -->

<!-- /site:field integrationPattern -->

<!-- /DOCS:SECTION -->

<!-- DOCS:SECTION id="module-architecture" -->
## Module Architecture

<!-- site:meta group="The Agentic Loan Applications Solution" -->

### Summary
<!-- site:field summary -->
The module architecture organizes the solution into workflow, applications, banking agents, core services, horizontal/common services, and integration services.
<!-- /site:field summary -->

### Summary HTML
<!-- site:field summaryHtml -->

<!-- /site:field summaryHtml -->

### Image Reference
<!-- site:field image -->
![Module Architecture image](images/ModuleArchitecture.png)
<!-- /site:field image -->

### Body Text
<!-- site:field bodyText -->

<!-- /site:field bodyText -->

### Key Points
<!-- site:field keyPoints -->

<!-- /site:field keyPoints -->

### Ordered Items
<!-- site:field orderedItems -->

<!-- /site:field orderedItems -->

### HTML Content
<!-- site:field htmlContent -->
<section class="best-practices" aria-labelledby="module-architecture-best-practices">
  <h3 id="module-architecture-best-practices">Architecture Principles</h3>
  <p>These architecture principles must always be followed for a sound solution design. To avoid unwanted dependencies that prevent correct module isolation and lifecycle management, follow these two rules:</p>
  <ul class="key-points">
    <li><strong>Only Downward Layer references</strong> - A dependency on an upper-layer module represents an incorrect reference from a producer to one of its natural consumers.</li>
    <li><strong>Only left to right references across columns</strong> - Business dependencies flow from the more specific to the more generic components. Horizontal components must not depend on industry components, which keeps them industry-agnostic and reusable everywhere. Common industry components must not depend on specific capabilities, which are add-ons that should be easy to opt in or out of.</li>
  </ul>
  <p>The leftmost <strong>Custom Composition</strong> column is the most specific layer of the solution and exists precisely to be tailored to each corporation. Because it sits to the left of every other column, it is allowed to depend on any add-on, common banking, or horizontal module, so the modules placed there are meant to be customized rather than treated as exceptions to the rules above. Two modules ship in this column:</p>
  <ul class="key-points">
    <li><strong>Banking Sync Services</strong> is customized to orchestrate data synchronization across the different core services. As a custom composition it legitimately references the several core services it coordinates — the one documented Core-to-Core orchestration case — threading the last-successful-sync checkpoint through each domain while every core service retains ownership of its own data. Each corporation adapts it to the domains and sync cadence it actually runs.</li>
    <li><strong>Mobile Banking</strong> is customized to compose the customer-facing mobile experience from capabilities exposed by any add-on. Sitting in the most specific column, it may consume from the lending add-on and the common banking modules alike, letting a corporation assemble the exact mobile journeys it needs without modifying the underlying industry or horizontal modules.</li>
  </ul>
</section>
<!-- /site:field htmlContent -->

### Integration Pattern
<!-- site:field integrationPattern -->

<!-- /site:field integrationPattern -->

<!-- /DOCS:SECTION -->

<!-- DOCS:SECTION id="business-workflow-and-status-machine" -->
## Business Workflow And Status Machine

<!-- site:meta group="The Agentic Loan Applications Solution" -->

### Summary
<!-- site:field summary -->
The business process combines workflow steps with automatic operations on state-machine transactions; workflow owns asynchronous orchestration while loan services own synchronous status changes.
<!-- /site:field summary -->

### Summary HTML
<!-- site:field summaryHtml -->

<!-- /site:field summaryHtml -->

### Image Reference
<!-- site:field image -->
![Business Workflow And Status Machine image](images/BusinessWorkflow.png)
<!-- /site:field image -->

### Body Text
<!-- site:field bodyText -->
The **Lending Application Workflow** process contains the following high-level flow. Decision points are not represented as separate steps; their outcomes appear as transition status labels between business activities. Automatic work that must finish as part of a status change belongs in **Lending Services**, not in a later asynchronous workflow step or in UI logic.
<!-- /site:field bodyText -->

### Key Points
<!-- site:field keyPoints -->
- Workflow customization belongs in **Lending Application Workflow** when it changes orchestration, task ownership, timing, branching, exception paths, or handover to another actor.
- Use workflow activities for handovers to people, agents, or APIs that do not need to complete synchronously, and for transitions worth logging in workflow progression.
- Use **Lending Services** ServiceLoanApplicationSetStatus for automatic transition work that must complete synchronously, such as initializing loan options when a status becomes approved.
- Do not model automatic same-actor preparation work as asynchronous workflow if the next screen depends on the result.
- Do not customize business-process rules in the UI; screens should only request status changes through service actions.
<!-- /site:field keyPoints -->

### Ordered Items
<!-- site:field orderedItems -->
1. A new loan application starts the workflow through the LoanApplicationStarted event.
2. The customer and loan agent work through application submission, with internal loan-agent states progressing through IntentCaptured, GapsIdentified, DocumentsValidated, and ReadyForAnalysis, or escalating to officer validation through Escalated.
3. The workflow runs OFAC screening once the application is ready for analysis.
4. The workflow runs risk/fraud assessment and can move directly to credit check or request officer validation.
5. The workflow runs credit check and sends the CreditChecked result toward officer validation.
6. A loan officer validates the application when the process is escalated, resumed, flagged for validation, or returned from credit check.
7. The customer reviews the final offer and either accepts, rejects, or times out.
8. Accepted offers create the loan account and close the successful path.
9. Rejected, not validated, not accepted, or timed-out paths generate the adverse action notice and close the unsuccessful path.
<!-- /site:field orderedItems -->

### HTML Content
<!-- site:field htmlContent -->
<section class="process-definition" aria-label="Business workflow customization">
  <div class="process-definition-header">
    <h3>Customizing Business Workflow And Status Machine</h3>
    <p>
      The business process is defined in two central points: orchestrating the macro process via workflows,
      or handling synchronous transactions via the status machine.
    </p>
  </div>
  <div class="process-definition-grid">
    <article class="process-definition-card">
      <div class="process-definition-icon" aria-hidden="true">
        <svg viewBox="0 0 48 48" focusable="false">
          <path d="M23 7h18v12H23zM7 29h18v12H7zM31 29h10v12H31zM24 19v6H12v4M24 25h12v4" />
        </svg>
      </div>
      <p class="process-definition-step">1. Workflow Steps</p>
      <h4><strong>Lending Application Workflow</strong></h4>
      <p>Orchestrates User, Agentic, and Automatic steps to define the macro process.</p>
      <figure class="slide-image-wrap process-definition-image process-definition-workflow-image">
        <img class="slide-image" src="images/Workflow.png" alt="Lending Application Workflow process flow">
      </figure>
      <p class="process-definition-label">WHEN TO USE</p>
      <ul>
        <li>Each step has a well-defined actor and final goal that must be achieved to be closed, and can be handed over assynchronously to the next step.</li>
        <li><span class="process-definition-warning-sign" aria-hidden="true">⚠️</span> Avoid consecutive steps or automatic steps between human steps for the same user to prevent race conditions.
          <ul>
            <li>If the UI must synchronously react to state transitions, it can't depend on the next workflow step to tell it what to do next, since we don't know when that step will be instantiated. Workflow activities are created asynchronously and there is no guarantee that the UI and workflow remain aligned with the status machine.</li>
            <li>In such cases, merge the steps into a single human step that closes on the final expected status, and execute any intercalated automatic step synchronously through the status machine described next.</li>
          </ul>
        </li>
      </ul>
    </article>
    <article class="process-definition-card">
      <div class="process-definition-icon" aria-hidden="true">
        <svg viewBox="0 0 48 48" focusable="false">
          <path d="M24 6a18 18 0 1 1-15.6 9M8 7v8h8M24 14v10l7 5" />
          <path d="M33 13l3-3M39 17l4-1M35 36l3 3M13 36l-3 3" />
        </svg>
      </div>
      <p class="process-definition-step">2. Status Machine</p>
      <h4>ServiceLoanApplicationSetStatus</h4>
      <p>Executes synchronously on status transactions performed by the service action.</p>
      <p class="process-definition-label">WHEN TO USE</p>
      <ul>
        <li>For automatic steps requiring real-time, synchronous UI feedback.</li>
        <li>For example, initialize Loan Offer Options immediately upon status changing to &quot;CreditChecked&quot;.</li>
      </ul>
      <figure class="slide-image-wrap process-definition-image process-definition-status-image">
        <img class="slide-image" src="images/SynchronousOperations.png" alt="Synchronous status operations inside LoanApplicationSetStatus">
      </figure>
    </article>
  </div>
  <aside class="process-definition-warning">
    <div class="process-definition-icon warning" aria-hidden="true">
      <svg viewBox="0 0 48 48" focusable="false">
        <path d="M24 6a18 18 0 1 0 0 36 18 18 0 0 0 0-36zM24 14v14M24 34h.01" />
      </svg>
    </div>
    <p>
      <strong>Don't customize the business process on the UI.</strong>
      The maximum responsibility of the UI is simply to call the status change service, for example when a user clicks an Approve button.
    </p>
  </aside>
  <section class="customization-subsection" aria-label="Loan application micro status versus progress views">
    <h3>LoanApplication Micro Status Versus Progress Views</h3>
    <p>
      <strong>Lending Services</strong> keeps the detailed loan state in the static entity LoanApplicationStatus and groups those detailed states through LoanApplicationStatusGroup. The status entity is the micro status used by services and workflow transitions, while the group entity is the stage shown in back-office progress views.
    </p>
    <p>
      Each LoanApplicationStatus record has a StatusGroupId that points to a LoanApplicationStatusGroup record. Back-office screens can use the group label, color, and order to show a simplified, linearized application journey, even when the underlying workflow has branches, retries, escalations, and terminal outcomes.
    </p>
    <ul class="key-points">
      <li>The current stage sequence is Draft, Risk Assessment, Credit Check, Referred, Offer, Accepted or Rejected. Flagged exists for exceptional validation and escalation states, but it is not displayed as a standalone progress-view stage.</li>
      <li>Draft groups early and resumable statuses such as Started, IntentCaptured, GapsIdentified, DocumentsValidated, ReadyForAnalysis, Resume, and NeedEscalation. These draft states are controlled by <strong>Lending Conversation Agent</strong>, not by the workflow.</li>
      <li>Risk Assessment and Credit Check group the automated analysis states, while Referred and Offer represent the officer-review and customer-offer portions of the journey.</li>
      <li>Accepted and Rejected represent terminal outcomes. When a micro status is grouped as Flagged, the progress view keeps showing the previous stage and adds a flag indicator that Loan Officer intervention is required.</li>
    </ul>
    <section class="customization-subsection" aria-label="Status messaging attributes">
      <h3>Status messaging</h3>
      <p>The Status records have special attributes to support UI interaction.</p>
      <ul class="key-points">
        <li>ProgressMessage stores the optional user-facing message associated with the micro status. LoanApplicationSetStatus sends it through LoanApplicationSendMessageToUser when the value is not empty, and uses the Resume status message to update the central agent memory in Lending Services. Blank values avoid creating a progress message for purely internal transitions.</li>
        <li>IsLongRunOperation marks statuses where the visible message represents work that may continue after the status transition. LoanApplicationSetStatus passes it as the WillContinueProcessing flag so consuming screens can keep the progress experience in a waiting or processing state, for example during CreditCheck.</li>
      </ul>
    </section>
  </section>
</section>
<!-- /site:field htmlContent -->

### Integration Pattern
<!-- site:field integrationPattern -->

<!-- /site:field integrationPattern -->

<!-- /DOCS:SECTION -->

<!-- DOCS:SECTION id="user-applications" -->
## User Applications

<!-- site:meta group="The Agentic Loan Applications Solution" -->

### Summary
<!-- site:field summary -->
User applications provide customer and staff access to the loan journey while keeping business rules in shared workflow and service modules.
<!-- /site:field summary -->

### Summary HTML
<!-- site:field summaryHtml -->

<!-- /site:field summaryHtml -->

### Image Reference
<!-- site:field image -->
![User Applications image](images/UserApplications.png)
<!-- /site:field image -->

### Body Text
<!-- site:field bodyText -->

<!-- /site:field bodyText -->

### Key Points
<!-- site:field keyPoints -->
- **Mobile Banking** is the customer-facing mobile channel for initiating or following up on loan applications.
- **Lending Console** is the operational staff application for visibility and intervention in loan-related work.
- Applications consume services and agents rather than owning durable loan-origination business rules directly.
- Back-office review queues, evidence panels, communication actions, and decision actions should remain role-controlled and service-backed.
<!-- /site:field keyPoints -->

### Ordered Items
<!-- site:field orderedItems -->

<!-- /site:field orderedItems -->

### HTML Content
<!-- site:field htmlContent -->

<!-- /site:field htmlContent -->

### Integration Pattern
<!-- site:field integrationPattern -->

<!-- /site:field integrationPattern -->

<!-- /DOCS:SECTION -->

<!-- DOCS:SECTION id="banking-agents" -->
## Banking Agents

<!-- site:meta group="The Agentic Loan Applications Solution" -->

### Summary
<!-- site:field summary -->
Banking agents support origination conversations, policy explanation, document validation, risk/fraud assessment, and loan communications.
<!-- /site:field summary -->

### Summary HTML
<!-- site:field summaryHtml -->

<!-- /site:field summaryHtml -->

### Image Reference
<!-- site:field image -->
![Banking Agents image](images/BankingAgents.png)
<!-- /site:field image -->

### Body Text
<!-- site:field bodyText -->

<!-- /site:field bodyText -->

### Key Points
<!-- site:field keyPoints -->
- **Lending Conversation Agent** is a state-driven conversational agent for personal unsecured loan origination, with strict JSON output and tool-use contracts.
- **Lending Policy Agent** answers policy and product questions only from supplied documentation and must mark unsupported information as not found.
- **Banking Document Agent** validates loan application evidence with a presumption of validity unless concrete discrepancies are found.
- **Lending Fraud Agent** identifies evidence-anchored fraud indicators, KYC/AML gaps, and credit-risk indicators without making legal conclusions.
<!-- /site:field keyPoints -->

### Ordered Items
<!-- site:field orderedItems -->

<!-- /site:field orderedItems -->

### HTML Content
<!-- site:field htmlContent -->
<section class="customization-subsection" aria-label="Banking agent customization">
  <h3>Customizing Banking Agents</h3>
  <p>Banking agent customization should identify the prompt-definition pattern first, then update the smallest owning prompt concern while keeping durable decisions, integrations, audit, and workflow routing in deterministic services.</p>
  <p>The banking agents use two prompt-definition patterns. <strong>Lending Conversation Agent</strong> uses a direct pattern where the system prompt is defined in a single assignment node. Generated banking agents such as <strong>Banking Document Agent</strong>, <strong>Lending Policy Agent</strong>, and <strong>Lending Fraud Agent</strong> use the preferred concern-based AgentDefinition pattern, where BuildSystemPrompt calls Def1_Goal, Def2_Workflow, Def3_Knowledge, Def4_Tools, Def5_Guardrails, Def6_Profile, and Def7_Output.</p>
  <p>For concern-based agents, customize the concern that owns the behavior being changed rather than rewriting the full system prompt. The default Prompt value on each Def action is the reusable baseline. Extension fields such as ExtendedGoal, ExtendedWorkflow, ExtendedKnowledge, ExtendedTools, ExtendedGuardrails, and OutputDefinition can layer corporation-specific additions over that baseline when the change is additive and does not contradict the default behavior.</p>
  <p><strong>Banking Document Agent</strong> is a good example. Its prompt defines an evidence-analysis agent that receives a grounded loan application object and supporting files, classifies documents, extracts visible values verbatim, normalizes values only for comparison, validates fields against evidence and match policies, checks freshness and expiration, verifies cross-document consistency and arithmetic, screens for large unsourced deposits, masks sensitive identifiers, and returns a strict JSON recommendation.</p>
  <div class="image-ordered-layout">
    <figure class="slide-image-wrap">
      <img class="slide-image" src="images/PromptDefinition.png" alt="Prompt definition pattern for banking agents">
    </figure>
    <ol class="ordered-points">
      <li>Use Def1_Goal/Prompt to define what the agent is responsible for and where its authority ends. Examples include whether the agent guides application intake, explains approved policy content, summarizes risk indicators, drafts customer communications, or reviews supplied evidence without making final business decisions.</li>
      <li>Use Def2_Workflow/Prompt to describe the agent's reasoning and interaction sequence. Examples include collecting missing application details, checking supplied context before answering, comparing evidence before recommending next steps, escalating unclear cases, or preparing a response for human review.</li>
      <li>Use Def3_Knowledge/Prompt to define the business knowledge, policies, grounding sources, and interpretation rules the agent may use. Examples include product eligibility rules, required consent language, document and evidence expectations, risk signal definitions, communication tone standards, and source-of-truth precedence.</li>
      <li>Use Def4_Tools/Prompt to define which approved actions, services, or integration services the agent may call and under what conditions. Examples include looking up application context, retrieving policy content, requesting a normalized risk summary, drafting a message from supplied data, or escalating when a required tool is unavailable.</li>
      <li>Use Def5_Guardrails/Prompt to set enforceable behavior limits across safety, compliance, privacy, grounding, advice boundaries, and prompt-injection resistance. Examples include not inventing facts, not bypassing consent, masking sensitive data, avoiding legal or financial advice, and requiring human review for unsupported or high-impact outcomes.</li>
      <li>Use Def6_Profile to tune runtime operating style without changing stable business rules. Examples include concise versus detailed explanations, proactive versus reactive questioning, conservative versus exploratory reasoning, customer-facing tone, staff-facing tone, and escalation sensitivity.</li>
      <li>Use Def7_Output/Prompt to define the response contract expected by consuming screens, services, or workflows. Examples include strict JSON for automation, a staff recommendation summary, a customer-safe explanation, not-found or escalation states, confidence or evidence fields, and length or formatting limits.</li>
      <li>Validate customized agents with scenarios that cover their real responsibilities, including happy path, missing context, conflicting evidence, unsupported policy questions, tool failure, escalation, privacy masking, prompt injection, and consumer parsing of the expected output shape.</li>
    </ol>
  </div>
  <section class="customization-subsection" aria-label="Model recommendations">
    <h3>Model recommendations</h3>
    <p>Use these LLM picks for the evaluated banking agents. They reflect May–July 2026 comparison runs on the current prompt and eval suites. Revisit them after a material prompt change, eval-suite update, or Bedrock pricing or timeout change.</p>
    <ul class="key-points">
      <li><strong>Lending Policy Agent</strong> — Primary: <strong>Claude Sonnet 4.6</strong>. Budget: <strong>Claude Haiku 4.5</strong> for internal or human-in-the-loop use. Sonnet matches Opus quality in human review at about one-third the cost; Haiku’s gap includes real scope-guardrail failures.</li>
      <li><strong>Banking Document Agent</strong> — Primary: <strong>Claude Opus 4.7</strong>. No budget alternative for customer-impacting work: Haiku has a critical PII-masking failure. Prefer Opus 4.6 only if Opus 4.7 cost is a hard constraint.</li>
      <li><strong>Lending Fraud Agent</strong> — Primary: <strong>Claude Haiku 4.5</strong> (leads on quality at about one-fifth Opus cost). Prefer Opus 4.7 only when adversarial document-injection resistance is a specific concern. Re-evaluate after the next prompt iteration; this agent’s prompt is still early.</li>
    </ul>
  </section>
  <section class="customization-subsection" aria-label="Agent Evals">
    <h3>Agent Evals</h3>
    <p>Use ODC Agent Evals to create a golden dataset that evaluates <strong>Lending Conversation Agent</strong>. When you create the evaluation dataset, use these values:</p>
    <ul class="key-points">
      <li><strong>Dataset name</strong> — <code>LendingConversationGoldendataset</code>. Golden dataset to evaluate the Lending Conversation Agent.</li>
      <li><strong>Agentic app</strong> — Clone of Lending Conversation Agent</li>
      <li><strong>Service action</strong> — <code>EvalRunLoanOriginationAgent</code></li>
      <li><strong>Test cases</strong> — 8. Import them from this JSON file: <a href="https://solutions-lending-sample-docs.s3.us-east-1.amazonaws.com/dataset_lending+conversation+agent._testcases.json">dataset_lending conversation agent._testcases.json</a>.</li>
      <li><strong>Setup</strong> — <code>EvalSetup</code> (Clone of Lending Agents Evals)</li>
      <li><strong>Teardown</strong> — <code>EvalTeardown</code> (Clone of Lending Agents Evals)</li>
    </ul>
    <p><strong>Lending Agents Evals</strong> provides the setup and teardown actions that seed and clean the eight fixture scenarios before and after each evaluation run.</p>
  </section>
  <section class="best-practices" aria-labelledby="banking-agents-best-practices">
    <h3 id="banking-agents-best-practices">Best Practices</h3>
    <ul class="key-points">
      <li>Identify whether the agent uses a single-assignment system prompt or the concern-based AgentDefinition pattern before editing.</li>
      <li>In concern-based agents, update the smallest owning concern: goal, workflow, knowledge, tools, guardrails, profile, or output.</li>
      <li>Keep stable document policy, evidence rules, match tolerances, freshness windows, and source-of-truth precedence in Def3_Knowledge/Prompt.</li>
      <li>Keep output schemas and allowed recommendation values in Def7_Output/Prompt, and update all consumers, tests, audit storage, and downstream workflow or service logic when the response contract changes.</li>
      <li>Keep provider integrations, durable state changes, audit records, status transitions, task routing, and review decisions in service, workflow, or integration service modules rather than in prompt text.</li>
      <li>Use AgentDefinition extension fields for additive corporation-specific guidance; update the owning default Prompt value when the baseline behavior itself is wrong.</li>
      <li>Follow the model recommendations above for Policy, Document, and Fraud agents; do not swap in a cheaper model when that agent’s known failure modes include PII leakage or scope-guardrail breaks.</li>
    </ul>
  </section>
</section>
<!-- /site:field htmlContent -->

### Integration Pattern
<!-- site:field integrationPattern -->

<!-- /site:field integrationPattern -->

<!-- /DOCS:SECTION -->

<!-- DOCS:SECTION id="core-services" -->
## Core Services

<!-- site:meta group="The Agentic Loan Applications Solution" -->

### Summary
<!-- site:field summary -->
Core services own the durable business concepts, state changes, reusable data, and service operations used by apps, workflow, and agents.
<!-- /site:field summary -->

### Summary HTML
<!-- site:field summaryHtml -->

<!-- /site:field summaryHtml -->

### Image Reference
<!-- site:field image -->
![Core Services image](images/CoreServices.png)
<!-- /site:field image -->

### Body Text
<!-- site:field bodyText -->

<!-- /site:field bodyText -->

### Key Points
<!-- site:field keyPoints -->
- **Banking Sync Services** orchestrates the other core services, delegating to each one the synchronization of its own data. Each core service provides its own data synchronization with the Banking Core System.
- **Lending Services** is the central loan domain service module and owns concepts such as LoanApplication, LoanOffer, statuses, status groups, types, roles, and events. It also provides the central agent-memory service that supports lending conversations: persisting session memory and injecting operational messages (such as Loan Officer feedback when an escalated application resumes) so apps and agents consume conversation context without Core services depending on Agent modules. ServiceLoanApplicationSetStatus is the stable boundary for changing loan application state and writing status/audit evidence.
- **Banking Account Services** bridges approved loan outcomes into account management and delegates bank-system integration to **Banking Core Integration Services**.
- **Banking KYC Services** extends the generic Customer from Solutions Common Services, with banking customer identity, eligibility, and onboarding requirements and delegates to the Banking Core Services to sync account data and to create Loan Accounts.
- **Solutions Common Services** provides industry-agnostic common concepts such as Documents, Customers, Agents, and Employees. These concepts can be extended by industry-specific services, such as Banking KYC Services extending the generic Customer with banking-specific identity and eligibility attributes. It also owns AuditLog, which is used throughout the solution to audit business operations performed by a human, agent, or workflow automatic action.
<!-- /site:field keyPoints -->

### Ordered Items
<!-- site:field orderedItems -->

<!-- /site:field orderedItems -->

### HTML Content
<!-- site:field htmlContent -->
<section class="concept-lifecycle">
  <h3>Major Data Concept Lifecycle</h3>
  <p>
    The loan domain core services and their business entities, support the customer journey through a small set of durable records.
    A pre-approved offer may exist before the customer starts, but the submitted LoanApplication and
    the accepted option become the source for the final loan account.
  </p>
  <div class="image-ordered-layout">
    <figure class="slide-image-wrap">
      <img class="slide-image concept-lifecycle-image" src="images/ConceptLifeCycle.png" alt="Loan concept lifecycle diagram">
    </figure>
    <ol class="ordered-points">
      <li>
        <strong>Optional LoanOffer creation.</strong>
        A LoanOffer can be created before the customer starts the application, representing a
        pre-approved amount, duration, or pricing proposal.
      </li>
      <li>
        <strong>LoanApplication initialization from a pre-approved offer.</strong>
        When the customer follows the offer in the mobile app, a LoanApplication is initialized
        with the LoanOffer values so the customer can confirm them or adjust the requested values.
      </li>
      <li>
        <strong>LoanApplication creation without an offer.</strong>
        If no pre-approved offer exists, the customer creates a new LoanApplication directly in the
        mobile app and enters the desired loan amount, duration, and related request details.
      </li>
      <li>
        <strong>Validated LoanApplication produces offer options.</strong>
        After the LoanApplication is submitted and validated, three LoanOfferOption records are
        created for the customer. These options present different durations and monthly payments,
        and can include an amount adjusted by the loan officer.
      </li>
      <li>
        <strong>Accepted option updates the LoanApplication values.</strong>
        When the customer accepts one LoanOfferOption, the LoanApplication is updated with the
        accepted option amount, duration, and monthly payment values.
      </li>
      <li>
        <strong>Create a loan account.</strong>
        After the LoanApplication reflects the accepted option, <strong>Banking Account Services</strong> creates an
        Account of type Loan for the customer.
      </li>
    </ol>
  </div>
</section>

<section class="best-practices" aria-labelledby="core-services-best-practices">
  <h3 id="core-services-best-practices">Best Practices</h3>
  <p>Every core service module follows the same conventions, so once you understand one you can navigate and extend them all. These principles describe how the modules are shaped; the generated code is documented inline, so rely on it for exact signatures, flows, and field-level detail.</p>
  <ul class="key-points">
    <li>
      <strong>Layered write surface.</strong> Each core module exposes its business concepts as public entities and its transactions as public <em>Service&lt;Entity&gt;</em> actions, which are the only public write boundary consumed by agents and user applications. Internally each entity is written through three layers, and callers only ever touch the outermost one: auto-generated entity actions (the only database writers, kept private to the owning module), non-public CRUD wrappers that add mandatory-input validation and audit-field stamping, and the public service actions that record the business-audit entry. Because apps, workflow, and agents bind only to the public service actions, customizations have a single, predictable place to add validation or side effects and no consumer can bypass the audit trail.
    </li>
    <li>
      <strong>Consistent entity conventions.</strong> Business entities carry standard audit fields (who created or updated the record, and when); foreign keys use a non-blocking delete rule to keep publishes clean; reference (static) entities carry an explicit display order and an active flag, and where an entity has that flag deletes are soft rather than physical. Every entity and business attribute is described, so the data model is self-documenting.
    </li>
    <li>
      <strong>Everything that mutates is audited.</strong> Every public service action that performs a business operation with data side effects — the create, update, and delete wrappers as well as any other service action that changes durable state — writes one business-readable entry to the shared audit log owned by <strong>Solutions Common Services</strong>, identifying the caller — a human user, an AI agent, or an automatic process or workflow — and expressed at the level of the master (root) entity, so a change to a child record is recorded against its owning parent and the trail reads as a coherent history of the top-level business objects rather than a stream of low-level row edits.
    </li>
    <li>
      <strong>Clean cross-module boundaries.</strong> A module reads another module's data only through its public entities and writes only through its public service actions; it never calls another module's auto-generated entity actions, which are private and break at publish. Shared concepts such as customers, agents, and audit tags live once in the horizontal common services and are referenced, not duplicated.
    </li>
    <li>
      <strong>Registered actors and self-registering reference data.</strong> Any agent or automatic process must be registered and configured in the static entity LoanAgent so it can be recorded as the actor of a business action. Modules that introduce their own agent or audit-tag codes seed them into the shared registries automatically on publish, using an idempotent routine that only adds codes that are missing, so the registries stay in sync without manual data steps.
    </li>
  </ul>
</section>
<!-- /site:field htmlContent -->

### Integration Pattern
<!-- site:field integrationPattern -->

<!-- /site:field integrationPattern -->

<!-- /DOCS:SECTION -->

<!-- DOCS:SECTION id="product-eligibility-and-policy-rules" -->
## Product, Eligibility, And Policy Rules

<!-- site:meta group="The Agentic Loan Applications Solution" -->

### Summary
<!-- site:field summary -->
Product and policy customization defines the loan catalog, eligibility, pricing, disclosures, policy lookup content, and decline logic.
<!-- /site:field summary -->

### Summary HTML
<!-- site:field summaryHtml -->

<!-- /site:field summaryHtml -->

### Image Reference
<!-- site:field image -->

<!-- /site:field image -->

### Body Text
<!-- site:field bodyText -->
The current solution keeps product, eligibility, and policy rules in two prompt-level sources.

**Lending Policy Agent** answers product and policy questions from the supplied banking policy documents only. Those documents are where the demo solution holds product facts such as eligibility text, rates, fees, limits, disclosures, procedures, and policy explanations that need document-grounded citations.

**Lending Conversation Agent** also contains prompt rules that control the customer-facing origination conversation. Its prompt defines when the agent must call policy lookup before making a policy-sensitive statement, how to treat lawful personal-loan purposes, when to escalate out-of-scope products, when to validate purpose during standard capture, and when to skip that check for pre-approved offers that have already been validated.

These built-in rule locations explain how the sample solution is assembled, but they are not the recommended long-term customization model for corporation-owned decision logic. For production customization, durable product and eligibility rules should be externalized into a rules engine or decision service with explicit ownership, versioning, approval workflow, auditability, and test coverage. The OutSystems services and workflows should call that rules engine for executable decisions, while the agents explain, collect information, and orchestrate the conversation using the decision results.
<!-- /site:field bodyText -->

### Key Points
<!-- site:field keyPoints -->
- Update policy documents when product facts, rates, fees, eligibility wording, disclosures, procedure text, or policy-support answers need to change.
- Update **Lending Policy Agent** when the way the agent grounds, cites, structures, or refuses policy answers needs to change.
- Update **Lending Conversation Agent** when conversational rule behavior changes, such as purpose capture, pre-approval handling, escalation wording, or policy-lookup tool usage.
- Use an external rules engine as the recommended customization point for executable eligibility, pricing, affordability, campaign, relationship-pricing, adverse-action, effective-date, and approval rules.
- Keep prompts as an explanation and orchestration layer; do not make prompt text the system of record for auditable policy decisions.
<!-- /site:field keyPoints -->

### Ordered Items
<!-- site:field orderedItems -->
1. Inventory each product or policy rule and classify it as document explanation, conversational behavior, executable decision logic, workflow branching, or persisted configuration.
2. Put document-explanation rules in the banking policy documents consumed by **Lending Policy Agent**, then verify that the agent cites those documents and marks unsupported information as not found.
3. Put conversational rules in **Lending Conversation Agent** only when they control how the agent asks questions, calls policy lookup, handles pre-approved offers, or escalates unsupported loan purposes.
4. Put durable decision rules in an external rules engine or decision service, especially when the rule affects eligibility, pricing, affordability, adverse-action reasons, approval thresholds, campaign treatment, or regulatory outcomes.
5. Integrate the external rules engine through **Lending Services** and workflow orchestration so service actions persist the decision, status, audit event, and reason codes returned by the rule evaluation.
6. Validate changes with scenarios covering supported and unsupported purposes, missing or conflicting policy documents, pre-approved offers, standard loan capture, rule-engine approvals and declines, adverse-action explanations, and rule-version changes.
<!-- /site:field orderedItems -->

### HTML Content
<!-- site:field htmlContent -->

<!-- /site:field htmlContent -->

### Integration Pattern
<!-- site:field integrationPattern -->

<!-- /site:field integrationPattern -->

<!-- /DOCS:SECTION -->

<!-- DOCS:SECTION id="integration-gateways" -->
## Integration and connectivity

<!-- site:meta group="The Agentic Loan Applications Solution" -->

### Summary
<!-- site:field summary -->
Integration Service modules isolate provider-specific APIs behind stable solution contracts for credit, regulatory, and banking-system integration.
<!-- /site:field summary -->

### Summary HTML
<!-- site:field summaryHtml -->

<!-- /site:field summaryHtml -->

### Image Reference
<!-- site:field image -->
![Integration and connectivity image](images/IntegrationServices.png)
<!-- /site:field image -->

### Body Text
<!-- site:field bodyText -->

<!-- /site:field bodyText -->

### Key Points
<!-- site:field keyPoints -->
- **Credit Integration Services** abstracts credit bureau, credit scoring, affordability, and credit-decisioning integrations.
- **Banking Regulatory Integration Services** abstracts regulatory and compliance integrations such as OFAC, FinCEN/BSA, SSA eCBSV, DMDC MLA/SCRA, and fair-lending checks.
- **Banking Core Integration Services** abstracts account-creation and operational banking APIs consumed through **Banking Account Services**.
- Integration Service documentation currently includes canonical interface detail and placeholders for identity, endpoints, protocol, mappings, resilience, security, observability, lifecycle, testing, and certification.
<!-- /site:field keyPoints -->

### Ordered Items
<!-- site:field orderedItems -->

<!-- /site:field orderedItems -->

### HTML Content
<!-- site:field htmlContent -->
<section class="customization-subsection" aria-label="Integration service customization">
  <h3>Customizing Integration and connectivity</h3>
  <p>Corporation integrations should preserve the boundary between solution services and provider-specific details.</p>
  <ul class="key-points">
    <li>Application, workflow, and agent modules should call solution services; solution services should call stable Integration Service contracts. Apps, workflow, and agents must never call an Integration Service or an external system directly.</li>
    <li>Provider-specific endpoints, credentials, payload mappings, retry policies, certification logic, and operational details belong inside Integration Service or adapter modules, so callers see only canonical, normalized inputs and outputs and a provider can be swapped or re-wired without touching callers.</li>
    <li>Integration Service modules are low-code libraries that expose their contract as public Server Actions — the canonical public API of an ODC library — with each concept's structures and actions grouped under a folder named for the concept. Keep every public action, parameter, and structure described so the contract stays self-documenting for the teams that later wire it to a real provider.</li>
    <li>The current integrations are mockups that return sample data: the mock and the sample data it reads form one contract, so cross-module references use the producer's natural business key rather than an internal identifier and every foreign key is populated. Customization replaces the mock body with the real provider call while keeping the same public contract.</li>
    <li>Customization areas include core banking, CIF/CRM, credit bureau, regulatory screening, document platforms, notification platforms, identity providers, enterprise integration layers, analytics feeds, and logging platforms.</li>
    <li>Integration work should define identifiers, environment configuration, canonical-to-provider mappings, audit/correlation requirements, contract tests, sandbox runs, and operational runbooks.</li>
  </ul>
  <section class="customization-subsection" aria-label="Customer-owned core banking connector">
    <h3>Building a customer-owned core banking connector</h3>
    <aside class="process-definition-warning" role="note" aria-label="Important disclaimer">
      <span class="process-definition-warning-sign" aria-hidden="true">!</span>
      <p><strong>Disclaimer.</strong> OutSystems does not provide or certify a Fiserv or Jack Henry connector. Those names are examples of core banking systems a customer may already use. This is not a partnership or endorsement. Customers build and maintain their own connector, using their own vendor access, credentials, and documentation.</p>
    </aside>
    <p>Use this shared approach when you replace the <strong>Banking Core Integration Services</strong> mocks with calls to your core banking system. The same OutSystems pattern applies whether your target is Fiserv, Jack Henry, or another core platform you already use.</p>
    <ol class="ordered-points">
      <li><strong>Keep the solution contract.</strong> Do not change the public Server Actions and structures on <strong>Banking Core Integration Services</strong> (for example retrieval actions such as <code>BankCoreIS_GetAllAccounts</code> and account-creation style operations). Those contracts are what <strong>Banking Account Services</strong> and <strong>Banking Sync Services</strong> already call.</li>
      <li><strong>Stay in the Integration layer.</strong> Put endpoints, authentication, payload mapping, paging, retries, timeouts, and provider error codes only inside the Integration Service (or a thin adapter it owns). Apps, workflow, and agents must never call the core banking API directly.</li>
      <li><strong>Consume the vendor API in ODC.</strong> Using your vendor’s documentation, add a REST/consumed API (or equivalent) for the operations you need. Store base URLs, client identifiers, and secrets in environment configuration or a secrets store — never hard-code credentials in actions or sample data.</li>
      <li><strong>Replace mock bodies, not signatures.</strong> For each public Integration action, keep the same inputs and outputs, then replace the sample-data mock with: validate inputs and session context → map to the provider request and authenticate → call the API and record integration evidence → normalize success and errors into the canonical OutSystems shapes → handle exceptions before the action ends.</li>
      <li><strong>Wire sync-safe retrieval.</strong> For synchronization retrieval actions, accept and forward the last-successful-sync watermark so the provider returns only changed records. Leave orchestration in <strong>Banking Sync Services</strong> and domain persistence in the core services.</li>
      <li><strong>Prove the contract.</strong> Contract-test every public action against sandbox responses, verify natural business keys (not internal GUIDs) for cross-module references, and run a sync plus account-creation path before promoting environments.</li>
    </ol>
    <p>For request and response field definitions, authentication schemes, and certification requirements, use only the documentation and support channels supplied under <strong>your</strong> agreement with the core banking vendor. This solution documentation describes the OutSystems Integration Service boundary, not the vendor’s product API.</p>
  </section>
</section>

<section class="best-practices" aria-labelledby="integration-gateways-best-practices">
  <h3 id="integration-gateways-best-practices">Best Practices</h3>
  <p>A highlight of the key points to follow when extending the Integration layer.</p>
  <ul class="key-points">
    <li><strong>Stable, solution-owned contract.</strong> Each Integration Service isolates one provider domain behind a stable contract; consumers bind to the contract, never to the provider.</li>
    <li><strong>Strictly layered.</strong> Only core services call Integration Service contracts; apps, workflow, and agents never call an integration or external system directly.</li>
    <li><strong>Provider detail stays inside.</strong> Endpoints, credentials, mappings, authentication, retries, timeouts, paging, and error normalization live inside the boundary and are never leaked upward.</li>
    <li><strong>Repeatable action pattern.</strong> Every action keeps the provider call behind the same wrapper — validate, map and authenticate, call and audit, normalize the output, and handle exceptions — and retrieval actions add a last-successful-sync timestamp so only changed records return.</li>
    <li><strong>Contracts first, fully described.</strong> Mocks already define the stable public contract that customization wires to a real provider; keep every public element described.</li>
    <li><strong>Customer-owned core banking connectors.</strong> When wiring a core banking platform (for example Fiserv or Jack Henry), replace Integration Service mocks behind the existing <strong>Banking Core Integration Services</strong> contract. Vendor names here are examples only — not a shipped or certified connector.</li>
  </ul>
</section>
<!-- /site:field htmlContent -->

### Integration Pattern
<!-- site:field integrationPattern -->
{
  "title": "Integration Service Action Pattern",
  "image": "images/IntegrationPattern.png",
  "description": "Integration Service actions should keep provider calls behind a repeatable wrapper: validate inputs and session context, prepare authenticated provider calls, execute and audit the call, normalize provider errors and outputs, and log exceptions.",
  "points": [
    "Validation / security logic checks consistency, session requirements, and user context before any external call.",
    "Input mappings / authentication prepare credentials and translate normalized inputs into the provider format.",
    "Call API / audit executes the provider operation and records integration evidence when required.",
    "Normalize error / output converts provider success, error, and exception shapes into expected OutSystems outputs.",
    "Error handling logs general and bank-specific exceptions before the action ends."
  ]
}
<!-- /site:field integrationPattern -->

<!-- /DOCS:SECTION -->

<!-- DOCS:SECTION id="data-sync-mechanism" -->
## Data Sync Mechanisms

<!-- site:meta group="The Agentic Loan Applications Solution" -->

### Summary
<!-- site:field summary -->
Data synchronization is centralized in **Banking Sync Services**, which orchestrates synchronization runs through core-service contracts while integration services remain the external-system boundary.
<!-- /site:field summary -->

### Summary HTML
<!-- site:field summaryHtml -->

<!-- /site:field summaryHtml -->

### Image Reference
<!-- site:field image -->

<!-- /site:field image -->

### Body Text
<!-- site:field bodyText -->
The Data Sync mechanism separates orchestration, domain ownership, and provider integration. **Banking Sync Services** coordinates synchronization runs and calls synchronization services exposed by the core modules. Core services remain responsible for domain rules, data normalization, persistence, audit evidence, and idempotent updates.

Integration Service modules remain the external-system boundary. The current integration services are mockups that return sample data, but they already define the contracts that can be wired to real external APIs during customization. Application, workflow, and agent modules should consume synchronized data through core services rather than calling integration services or external systems directly.
<!-- /site:field bodyText -->

### Key Points
<!-- site:field keyPoints -->
- Keep the three responsibilities separate — orchestration in **Banking Sync Services**, domain ownership (validation, mapping, persistence, audit) in the core services, and the provider boundary in the Integration Service modules — and never collapse them.
- Give each core service its own two-tier sync surface — a public synchronization action that fans out to one private per-entity action — and reuse an existing one rather than duplicating it.
- Thread the last-successful-sync timestamp through **Banking Sync Services**, the core service, and the Integration Service retrieval so each provider call returns only changed records.
- Advance a domain's checkpoint only after the core service has validated, mapped, persisted, and audited the retrieved slice; on failure preserve the previous checkpoint.
- Sync entities in foreign-key dependency order within a service, and call producer core services before consumer core services across services.
- Upsert idempotently on each record's stable external key (GUID) and resolve references from their external key to the local identifier before mapping foreign keys — never store a raw external key as an Id.
- Run the orchestration asynchronously on a timer, persisting a per-domain checkpoint and a run log, with a non-swallowing exception handler that aborts and logs on failure.
- Treat **Banking Sync Services** referencing the other core services as the one documented Core-to-Core exception; core services never depend back on it, and it never leaks up to apps, workflow, or agents.
- Use retrieval-style Integration actions such as BankCoreIS_GetAllAccounts as the sync pattern; transaction-oriented Integration Service actions are not synchronization-retrieval examples.
<!-- /site:field keyPoints -->

### Ordered Items
<!-- site:field orderedItems -->

<!-- /site:field orderedItems -->

### HTML Content
<!-- site:field htmlContent -->
<section class="customization-subsection" aria-label="Data synchronization customization">
  <h3>Customizing Data Sync Mechanisms</h3>
  <p>Customize Data Sync by wiring Integration Service retrieval actions to real external APIs while preserving <strong>Banking Sync Services</strong> orchestration, core-service ownership, and incremental last-sync checkpoints.</p>
  <p>At customization time, the main task is to replace mock Integration Service responses with real provider calls without changing the architectural ownership. <strong>Banking Sync Services</strong> should continue to start and monitor synchronization runs. Core services should continue to expose the synchronization operations and own validation, transformation, upsert behavior, audit evidence, and domain consistency. Integration Service modules should contain the provider endpoints, authentication, payload mapping, paging, retry behavior, timeout handling, and error normalization.</p>
  <p>The incremental sync pattern is based on a last-successful-sync timestamp. <strong>Banking Sync Services</strong> keeps the timestamp for each synchronization domain and passes it into the relevant core-service operation. The core service passes that timestamp to the Integration Service retrieval action, and the Integration Service uses it as the provider query boundary so only data updated since the previous successful synchronization is returned. For example, BankCoreIS_GetAllAccounts is the type of retrieval contract that can be wired to a corporation banking API; more retrieval actions can follow the same pattern as they are implemented.</p>
  <p>When a run succeeds, <strong>Banking Sync Services</strong> stores the new successful-sync timestamp for the next run. When a run fails or only partially succeeds, the previous checkpoint should be preserved or advanced only for the safely completed slice, depending on the corporation's retry and reconciliation policy.</p>
  <p>Each core service owns the synchronization of its own data through a two-tier surface: a single public synchronization action that fans out to one private per-entity action, each pulling from the matching Integration Service retrieval and idempotently upserting the result on the record's stable external key. Add this surface only to a core service that lacks it and reuse one that already exists rather than duplicating it. References arrive as the provider's external key — a GUID, email, account number, or reference-data label — and must be resolved to the local identifier before being mapped into a foreign key, so entities are synced in foreign-key dependency order (reference data first, then independent roots, then dependents) and, across services, producer services run before the consumers that reference them.</p>
  <p><strong>Banking Sync Services</strong> runs the orchestration asynchronously on a timer rather than as a user-facing action. The timer wakes a private run action that walks each domain in producer-to-consumer order, wrapping every synchronization call in an open/close run pair that reads the domain checkpoint, records a run, and advances the checkpoint on success only. It persists a per-domain checkpoint and a run log (status, timings, records processed and failed, and an operational message) and carries a non-swallowing catch-all exception handler that aborts the transaction and logs on failure, so a failed run leaves no half-committed state and stays visible in observability. Because it sits in the core layer yet references the other core services it orchestrates, it is the one documented Core-to-Core exception to the module-dependency rules; core services never depend back on it, and the exception never leaks upward into apps, workflow, or agents.</p>
  <ol class="ordered-points">
    <li>Define the synchronization domain, such as accounts, customers, employees, KYC data, transactions, loan reference data, or policy data.</li>
    <li>Identify the core service that owns that domain and expose or adapt its synchronization operation.</li>
    <li>Identify the Integration Service retrieval action that will fetch the external data, such as BankCoreIS_GetAllAccounts for account synchronization.</li>
    <li>Wire the Integration Service action to the external API, including endpoint configuration, authentication, query parameters, paging, timeout, and retry behavior.</li>
    <li>Pass the last-successful-sync timestamp into the Integration Service request so the provider returns records updated since the previous successful sync.</li>
    <li>Normalize the provider response and errors into the Integration Service contract expected by the core service.</li>
    <li>Let the core service validate, map, upsert, audit, and expose the synchronized data through its public service layer.</li>
    <li>Let <strong>Banking Sync Services</strong> record the run result, retry status, operational summary, and next checkpoint.</li>
  </ol>
</section>
<!-- /site:field htmlContent -->

### Integration Pattern
<!-- site:field integrationPattern -->

<!-- /site:field integrationPattern -->

<!-- /DOCS:SECTION -->

<!-- DOCS:SECTION id="audit-and-logging" -->
## Audit And Logging

<!-- site:meta group="The Agentic Loan Applications Solution" -->

### Summary
<!-- site:field summary -->
Audit and logging combine business-process evidence, operational evidence, and platform workflow-progress tracking.
<!-- /site:field summary -->

### Summary HTML
<!-- site:field summaryHtml -->

<!-- /site:field summaryHtml -->

### Image Reference
<!-- site:field image -->

<!-- /site:field image -->

### Body Text
<!-- site:field bodyText -->
Audit and logging provide traceability across business operations, integration calls, and workflow progression. Core services capture business-process evidence, Integration Service modules record operational evidence for provider interactions, and the platform workflow runtime keeps the visible process-progress history.
<!-- /site:field bodyText -->

### Key Points
<!-- site:field keyPoints -->

<!-- /site:field keyPoints -->

### Ordered Items
<!-- site:field orderedItems -->

<!-- /site:field orderedItems -->

### HTML Content
<!-- site:field htmlContent -->
<ul class="key-points audit-key-points">
  <li>
    <p><strong>Audit</strong> captures business-process evidence across services, workflow, agents, decisions, and support actions.</p>
    <p>Core services use <strong>Solutions Common Services</strong> ServiceAuditLogAdd to audit loan application changes, status transitions, external-check outcomes, decision inputs, officer overrides, account creation, and adverse-action generation.</p>
  </li>
  <li>
    <p><strong>Logging</strong> captures operational evidence such as errors and integration calls.</p>
    <p>Integration Service modules log provider metadata, request status, normalized error codes, retry attempts, timeout outcomes, and certification-relevant references.</p>
  </li>
  <li>
    <p><strong>Workflow progress</strong> is tracked by the platform workflow runtime and remains visible independently from business audit records.</p>
    <figure class="slide-image-wrap">
      <img src="images/AuditWorkflowProgress.png" alt="Workflow progress view showing completed Start and waiting SubmitApplication steps">
    </figure>
  </li>
</ul>
<!-- /site:field htmlContent -->

### Integration Pattern
<!-- site:field integrationPattern -->

<!-- /site:field integrationPattern -->

<!-- /DOCS:SECTION -->

<!-- DOCS:SECTION id="environment-operation-configuration-and-deployment" -->
## Make it your own

<!-- site:meta group="Getting Started" -->

### Summary
<!-- site:field summary -->

<!-- /site:field summary -->

### Summary HTML
<!-- site:field summaryHtml -->

<!-- /site:field summaryHtml -->

### Image Reference
<!-- site:field image -->

<!-- /site:field image -->

### Body Text
<!-- site:field bodyText -->

<!-- /site:field bodyText -->

### Key Points
<!-- site:field keyPoints -->

<!-- /site:field keyPoints -->

### Ordered Items
<!-- site:field orderedItems -->

<!-- /site:field orderedItems -->

### HTML Content
<!-- site:field htmlContent -->
<section class="temporary-support-list" aria-label="Temporary support list for environment settings">
  <h3>Configuration</h3>
  <p>This list captures settings, hardwired values, default values, and customization points found by inspecting the Loan Origination modules. Modules are grouped by architectural layer (Workflows, Apps, Agents, Core, Horizontal Components, Integration). It should be maintained as modules change until the formal environment, operations, and configuration model is defined. Prompt-embedded values (AI agents) and resource-embedded values (for example the adverse-action notice template) are called out where they could not be re-parsed literally in this pass.</p>
  <h4>Agent model configuration</h4>
  <p>Banking agents ship with the trial default model <code>TrialClaudeHaiku4_5</code>. Before production use, change each agent’s model from that default to the recommended model for that agent (see <a href="banking-agents.html">Banking Agents — Model recommendations</a>):</p>
  <ul class="key-points">
    <li><strong>Lending Policy Agent</strong> — change from <code>TrialClaudeHaiku4_5</code> to <strong>Claude Sonnet 4.6</strong>.</li>
    <li><strong>Banking Document Agent</strong> — change from <code>TrialClaudeHaiku4_5</code> to <strong>Claude Opus 4.7</strong>.</li>
    <li><strong>Lending Fraud Agent</strong> — change from <code>TrialClaudeHaiku4_5</code> to <strong>Claude Haiku 4.5</strong>.</li>
  </ul>
  <p>Leaving agents on <code>TrialClaudeHaiku4_5</code> is only for trial or early exploration. For customer-impacting Document workloads in particular, keep the recommended Opus model rather than a cheaper trial default.</p>
  <h4>Core banking connector</h4>
  <p>To connect your own core banking system (for example Fiserv or Jack Henry), follow <a href="integration-gateways.html">Integration and connectivity — Building a customer-owned core banking connector</a>. OutSystems does not ship a connector for those vendors.</p>

  <h4><strong>Lending Application Workflow</strong> <span class="layer-tag">(Workflows)</span></h4>
  <ul>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li>The <code>FinalOffer</code> human activity uses a fixed escalation timeout of <code>TimeoutBasicTime = 3</code> and <code>TimeoutUnit = Days</code>; the other human activities (<code>SubmitApplication</code>, <code>OfficerValidation</code>) have no timeout value set.</li>
        <li>Screening callbacks pass fixed flags <code>CreditCheck.IsCreditCheck = True</code> and <code>RiskFraudAssessment.IsCreditCheck = False</code>.</li>
        <li>Status-update reason text is hardwired as <code>"Risk flags raised"</code> (SetStatusToNeedValidation) and <code>"No issues found"</code> (SetStatusToCreditCheck); SetStatusToNotAccepted passes an empty reason <code>""</code>.</li>
        <li>Submission records a hardwired <code>StepNo = 1</code>.</li>
        <li>Automatic status-change activities hardwire the acting-agent identifier <code>AgentId = Entities.LoanAgent.LoanWorkflow</code> (and <code>NullTextIdentifier()</code> on SetStatusToNotAccepted).</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Lending Console</strong> <span class="layer-tag">(Apps)</span></h4>
  <ul>
    <li><strong>Settings.</strong>
      <ul>
        <li><code>SettingDashboardUseMockData</code> forces mock dashboard data, default <code>True</code> (demo flag).</li>
        <li><code>TaskUndoActionWaitInSeconds</code> controls the task-card undo wait time, default <code>5</code>.</li>
      </ul>
    </li>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li><code>DoLogin</code> error text is fixed as <code>"Invalid credentials."</code>, <code>"Login operation failed."</code>, and a "too many failed login attempts" message.</li>
        <li>Date-range filtering (<code>Aux_DateFilterHelper</code>) derives windows with <code>AddDays</code> from the selected <code>DateRange.DaysToFilter</code>, and dashboard/list logic uses fixed mock branches when the mock-data flag is on.</li>
        <li>The adverse-action notice is generated in this module; its disclosure literals (CRA name, address, phone, score range, dates) live in the notice template resource and were not re-verified in this pass.</li>
      </ul>
    </li>
    <li><strong>Default Values.</strong>
      <ul>
        <li>Static reference data <code>SidebarAction</code> (15 records), <code>LocaleCommon</code> (22), and <code>DateFormat</code> (9) back the navigation, locale, and formatting defaults.</li>
        <li>Client-side boolean state variables default to <code>False</code> (execution, popup, and selection flags).</li>
      </ul>
    </li>
    <li><strong>Customization Points.</strong>
      <ul>
        <li>Nine dashboard mock-data branches — the six dashboard metric cards plus <code>LoanProductivity_GetCounters</code>, the loan-volume chart, and <code>PipelineCustomView.GetList</code> — return mock results; replace each mock result with the real data-retrieval logic (governed by the <code>SettingDashboardUseMockData</code> flag).</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Mobile Banking</strong> <span class="layer-tag">(Apps)</span></h4>
  <ul>
    <li><strong>Settings.</strong>
      <ul>
        <li><code>EventPollingInterval</code> sets the event-polling trigger interval in seconds, default <code>5</code>.</li>
        <li><code>EventPollingTTL</code> sets the time-to-live of event-polling queue messages in seconds, default <code>10</code>.</li>
      </ul>
    </li>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li><code>GetFileFormat</code> maps extensions to fixed MIME types (<code>image/jpeg</code>, <code>image/png</code>, <code>image/webp</code>, <code>application/pdf</code>, <code>application/msword</code>, <code>application/vnd.ms-excel</code>, and the Office XML document/spreadsheet types); unmatched extensions raise <code>UnsupportedFileExtension</code>.</li>
        <li><code>DoLogin</code> error text is fixed (<code>"Invalid credentials."</code>, <code>"Login operation failed."</code>, and a "too many failed login attempts" message).</li>
      </ul>
    </li>
    <li><strong>Customization Points.</strong>
      <ul>
        <li><code>LoanApplication_OTPChecked</code> (validate user PIN).</li>
      </ul>
    </li>
    <li><strong>Default Values.</strong>
      <ul>
        <li>Static reference data such as <code>ForYou</code>, <code>Suffix</code>, <code>ValidationProgress</code>, <code>PaymentFrequency</code>, and <code>AccountDetailFilter</code> back the UI defaults.</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Lending Agents Evals</strong> <span class="layer-tag">(Apps)</span></h4>
  <p>Non-production evaluation harness for the lending agents; its runtime behavior is driven entirely by hardwired fixture literals.</p>
  <ul>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li>Every eval customer is created and matched by <code>Customer.CustomerNumber = "EVAL"</code>, and each fixture stamps <code>LoanApplication.ApplicationGUID = "EVAL-" + RawGuid</code> so the teardown sweep can find and remove it.</li>
        <li>Synthetic contacts are derived per fixture: email <code>RawGuid + "@eval.example.com"</code> and a fixed mobile <code>"+351912000000"</code>.</li>
        <li>Eight named scenario presets drive the fixtures (<code>"Eval Alice Approved"</code>, <code>"Eval Bob NoPaystub"</code>, <code>"Eval Carol HighAmount"</code>, <code>"Eval Dave Phone"</code>, <code>"Eval Erin Policy"</code>, <code>"Eval Frank Blank"</code>, <code>"Eval Grace PreApproved"</code>, <code>"Matthew Shelton"</code>), each seeding fixed loan-intent values (income, loan amount, purpose, term, employment) and synthetic PII (reserved <code>900-xx-xxxx</code> test SSNs, addresses, birth dates, employer, coordinates).</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Lending Conversation Agent</strong> <span class="layer-tag">(Agents)</span></h4>
  <ul>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li>Prompt content is versioned (currently <code>1.26.1</code>); the demo-mode behavior marker present in the prior revision has been removed.</li>
        <li>Prompt content includes the allowed workflow-state vocabulary (<code>Started</code>, <code>IntentCaptured</code>, <code>GapsIdentified</code>, <code>DocumentsValidated</code>, <code>NeedEscalation</code>, <code>ReadyForAnalysis</code>, <code>Escalated</code>, <code>Resume</code>), the required three-document set, a <code>30 days</code> pay-stub freshness rule, terminal-state rules, and a strict JSON output envelope (only <code>Answer</code> and <code>Options</code> keys).</li>
        <li><code>QualifyDocument</code> assigns a fixed <code>DocumentTypeId = 14</code> and confirmation text.</li>
      </ul>
    </li>
    <li><strong>Default Values.</strong>
      <ul>
        <li>Prompt defaults are embedded in the <code>BuildMessages</code> pattern; the module has no Site Property settings.</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Lending Policy Agent</strong> <span class="layer-tag">(Agents)</span></h4>
  <ul>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li>Behavior is defined by the agent system prompt (<code>Def1_Goal</code>…<code>Def7_Output</code> sections): answer only from supplied banking-product/policy documentation, mark unsupported information under <code>Not in the documents</code>, and emit a fixed <code>Banking Terms — {Product/Account}</code> Markdown template.</li>
        <li>Embedded prompt limits: at most <code>2</code> clarifying questions per interaction and quoted snippets <code>≤ 25 words</code>; tool policy is fixed to <code>"No external tools."</code> (<code>Def4_Tools</code>).</li>
      </ul>
    </li>
    <li><strong>Default Values.</strong>
      <ul>
        <li>Static <code>AgentProfile_*</code> reference data (Tone, Verbosity, Proactivity, ReasoningDepth, RiskTolerance, ActionAutonomy) back the agent behavior defaults; prompt defaults are embedded in the AgentDefinition actions (<code>Def6_Profile</code> carries no default literal and is assembled from the runtime profile).</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Banking Document Agent</strong> <span class="layer-tag">(Agents)</span></h4>
  <ul>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li>Prompt-level validation thresholds include zero income tolerance unless specified and <code>20%</code> income variance.</li>
        <li>Prompt-level validation thresholds include pay-frequency multipliers <code>12/26/52</code> and a <code>70%</code> deposit-to-income floor.</li>
        <li>Prompt-level validation thresholds include <code>$1.00</code> and <code>$0.01</code> rounding tolerances.</li>
        <li>Prompt-level validation thresholds include a large-deposit threshold of <code>50%</code> of gross monthly income or <code>$5,000</code>, freshness windows of <code>30/60/120 days</code>, and a <code>25%</code> variable-comp trigger requiring two years of tax returns.</li>
        <li>Output/guardrail literals: PII masked to the <code>last 4</code> characters, <code>Title &lt; 50</code> and <code>Description &lt; 500</code> character caps, and a fixed 8-category discrepancy taxonomy. These live in the system-prompt definition.</li>
      </ul>
    </li>
    <li><strong>Default Values.</strong>
      <ul>
        <li>Static <code>AgentProfile_*</code> reference data back the behavior defaults; prompt concern defaults (presumption of validity; conservative match policies) are embedded in the AgentDefinition actions.</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Lending Fraud Agent</strong> <span class="layer-tag">(Agents)</span></h4>
  <ul>
    <li><strong>Settings.</strong>
      <ul>
        <li><code>IsDemo</code> bypasses all fraud checks when set, default <code>True</code>.</li>
      </ul>
    </li>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li>Prompt-level credit-risk indicators include <code>DTI &gt; 43%</code>, <code>LTV &gt; 80%</code>, and employment stability <code>&lt; 2 years</code>.</li>
        <li>Prompt-level AML/currency thresholds include a <code>$10,000</code> CTR reporting threshold and structuring detection for <code>$9,000–$9,999</code> deposits (3+ within 7 days).</li>
        <li>Prompt-level loan-fraud tolerances include income overstated <code>&gt; 10%</code>, assets <code>&gt; 15%</code>, appraisal <code>&gt; 20%</code> over comparables, and <code>&gt; 3</code> applications within 90 days.</li>
        <li>Prompt-level KYC/transaction thresholds include beneficial-ownership disclosure at <code>≥ 25%</code> and transaction-pattern rules (for example <code>&gt; 5</code> transactions per 24h, round-amount, and dormancy flags). These live in the system-prompt definition.</li>
        <li>Guardrail limits: at most <code>2</code> clarifying questions, snippets <code>≤ 50 words</code>, PII masked to <code>last 4</code> digits, and confidence <code>≥ 0.9</code> reserved for corroborated findings.</li>
      </ul>
    </li>
    <li><strong>Default Values.</strong>
      <ul>
        <li>Static <code>AgentProfile_*</code> reference data back the behavior defaults; prompt concern defaults are embedded in the AgentDefinition actions.</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Lending Services</strong> <span class="layer-tag">(Core)</span></h4>
  <ul>
    <li><strong>Settings.</strong>
      <ul>
        <li><code>Currency</code> controls the formatting currency symbol, default <code>"$"</code>.</li>
        <li><code>GroupSeparator</code> controls the number group separator, default <code>","</code>.</li>
        <li><code>DecimalSeparator</code> controls the number decimal separator, default <code>"."</code>.</li>
        <li><code>EffectiveInterestRatePA</code> sets the default loan effective interest rate, default <code>0.085</code>.</li>
        <li><code>Test_CreditCheckWithTask</code> forces mock credit-check task creation for test purposes, default <code>False</code>.</li>
      </ul>
    </li>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li>The demo offer restart (<code>Sync_RestartLoanOffer</code>) writes a fixed sample offer: <code>PrincipalAmount = 60000</code>, <code>EffectiveInterestRatePA = 0.085</code>, <code>TermMonths = 48</code>, <code>GUID = "QWERT123ASD456"</code>, <code>OfferExpiryAt = AddDays(CurrDateTime(), 30)</code>, and <code>AccountType</code>/<code>InitialPurpose = "Personal Loan"</code>.</li>
        <li><code>LoanOfferOptionsAdd</code> hardwires <code>OneTimeProcessingFee = 150</code> and a fixed promise-to-pay text template (brand literal <code>"NeoBank"</code>).</li>
        <li><code>NotifyUser</code> uses fixed notification titles and bodies (for example <code>"Great news about your loan! 🎉"</code>).</li>
        <li>Audit <code>CreatedOn</code>/<code>UpdatedOn</code> stamps are set with <code>CurrDateTime()</code> throughout the CRUD wrappers.</li>
      </ul>
    </li>
    <li><strong>Default Values.</strong>
      <ul>
        <li>Static entities carry the loan domain reference data (for example <code>LoanApplicationStatus</code> with 18 records, status groups, types, roles, task statuses/priorities, and audit tags).</li>
        <li>The sample offer defaults above act as the demo restart profile.</li>
      </ul>
    </li>
    <li><strong>Customization Points.</strong>
      <ul>
        <li><code>LoanScreeningCredit</code>.</li>
        <li><code>LoanScreeningBorrower</code>.</li>
        <li><code>LoanOfferOptionsGenerate</code> for nominal-interest, effective-interest, and term multipliers.</li>
        <li><code>LoanOfferOptionsAdd</code> for monthly-payment, total-paid, and total-interest calculations.</li>
        <li><code>ServiceLoanApplicationAgreementGenerate</code> and <code>ServiceLoanApplicationAgreementGetURL</code>.</li>
        <li><code>ServiceLoanApplicationGenerateAdverseActionNotice</code> (create the adverse-action notice PDF).</li>
        <li><code>Document/OnAuthentication</code> (build your own authentication flow).</li>
        <li><code>SyncLoanApplications</code>.</li>
        <li><code>SyncLoanOffers</code>.</li>
        <li><code>SyncLoanOfferClauses</code>.</li>
        <li><code>SyncLoanPolicy</code>.</li>
        <li><code>SyncLoanApplicationTasks</code>.</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Banking Account Services</strong> <span class="layer-tag">(Core)</span></h4>
  <ul>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li>Audit <code>CreatedOn</code>/<code>UpdatedOn</code> stamps are set with <code>CurrDateTime()</code> (and <code>CreatedBy</code>/<code>UpdatedBy</code> with <code>GetUserId()</code>) in the account and transaction CRUD wrappers.</li>
      </ul>
    </li>
    <li><strong>Default Values.</strong>
      <ul>
        <li>Static reference data <code>AccountType</code> (6), <code>TransactionType</code> (17), <code>TransferDateOption</code> (3), and <code>TransactionCategory</code> (12) back the account/transaction defaults.</li>
      </ul>
    </li>
    <li><strong>Customization Points.</strong>
      <ul>
        <li><code>SyncAccounts</code>.</li>
        <li><code>SyncTransactions</code>.</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Banking KYC Services</strong> <span class="layer-tag">(Core)</span></h4>
  <ul>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li>Audit <code>CreatedOn</code> stamps are set with <code>CurrDateTime()</code> (and <code>CreatedBy</code> with <code>GetUserId()</code>) in the <code>KYCCustomer</code> CRUD wrapper.</li>
      </ul>
    </li>
    <li><strong>Customization Points.</strong>
      <ul>
        <li><code>SyncKYCCustomers</code>.</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Banking Sync Services</strong> <span class="layer-tag">(Core)</span></h4>
  <ul>
    <li><strong>Settings.</strong>
      <ul>
        <li><code>LoanRequestWorkflowKey</code> identifies the loan-request workflow referenced by the sync process (set per environment), default <code>"4826f7af-d570-4911-be66-5e68a059a6ba"</code>.</li>
      </ul>
    </li>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li>Workflow cleanup filters active process definitions with <code>ProcessDefinition.Key = Settings.LoanRequestWorkflowKey</code>.</li>
        <li>The three sync timers (<code>SyncData</code>, <code>SyncDelete</code>, <code>Sync_Recreate</code>) each carry a fixed <code>TimeoutInMinutes = 20</code>.</li>
        <li><code>SyncData</code> advances the per-domain watermarks (<code>LastSyncTimestamp*</code>) with <code>CurrDateTime()</code>.</li>
        <li>Sample screens append <code>" DESC"</code> when toggling table sort fields; the audit-log screen sorts by <code>"AuditLog.CreatedOn DESC"</code>.</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Solutions Common Services</strong> <span class="layer-tag">(Horizontal Components)</span></h4>
  <ul>
    <li><strong>Settings.</strong>
      <ul>
        <li><code>DevelopmentDomain</code> stores the development environment default domain URL, default <code>"solutions-dev.outsystems.app"</code>.</li>
      </ul>
    </li>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li><code>SampleData_IsEnabled</code> and <code>SyncTesting_IsEnabled</code> gate behavior by comparing <code>GetDefaultDomain.DefaultDomain</code> with <code>Settings.DevelopmentDomain</code>.</li>
        <li>Customer/employee picture sync sets <code>Filetype = "image/" + extension</code>; audit <code>CreatedOn</code> stamps use <code>CurrDateTime()</code>.</li>
      </ul>
    </li>
    <li><strong>Default Values.</strong>
      <ul>
        <li>Static reference data carries the shared defaults used across the solution: <code>AuditAction</code> (10), <code>DocumentType</code> (15), <code>Gender</code> (2), <code>StateProv</code> (51), and <code>DateRange</code> (4), plus customer, employee, job-title, branch, and region entities.</li>
      </ul>
    </li>
    <li><strong>Customization Points.</strong>
      <ul>
        <li><code>SyncBranches</code>.</li>
        <li><code>SyncCustomers</code>.</li>
        <li><code>SyncCustomerPictures</code>.</li>
        <li><code>SyncEmployees</code>.</li>
        <li><code>SyncEmployeePictures</code>.</li>
        <li><code>SyncJobTitles</code>.</li>
        <li><code>SyncRegions</code>.</li>
        <li><code>DocumentCreate</code> (default stores the document binary in the DB; can be pointed at external storage such as S3 via <code>Document.StorageKey</code>).</li>
        <li><code>DocumentGetContent</code> (implement custom storage retrieval).</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Solutions Common Patterns</strong> <span class="layer-tag">(Horizontal Components)</span></h4>
  <ul>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li><code>GetMimeType</code> maps file extensions to fixed MIME types (PDF, Word/Office XML document, Excel/Office XML spreadsheet, PNG, JPEG, GIF, WebP, CSV, HTML, Markdown, and plain text), returning empty text for unknown extensions.</li>
      </ul>
    </li>
    <li><strong>Default Values.</strong>
      <ul>
        <li>None — this is a stateless horizontal library of reusable UI patterns, utility actions, and data converters.</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Credit Integration Services</strong> <span class="layer-tag">(Integration)</span></h4>
  <ul>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li>Credit-check retry behavior uses <code>TrialsLeft = 5</code> and <code>Sleep(Time = 10000)</code>.</li>
        <li>Mock result values include application <code>"LOAN-APP-100023"</code>, applicant <code>"APP-001"</code>, provider <code>EXPERIAN</code>, inquiry type <code>SOFT_PULL</code>, status <code>COMPLETED</code>, and timestamps <code>2026-06-01T10:30:00Z</code>/<code>2026-06-01T10:30:03Z</code>; the request id is <code>"CC-" + ApplicationId</code>.</li>
        <li>Mock credit summary values include <code>TotalDebt = 18630</code>, <code>TotalOpenAccounts = 7</code>, <code>TotalClosedAccounts = 12</code>, <code>OldestAccountAgeMonths = 144</code>, <code>CreditCardBalance = 2500</code>, <code>CreditCardLimit = 10000</code>, <code>CreditCardUsePercentage = 0.25</code>, <code>AutoLoanDebt = 8500</code>, <code>OtherDebt = 7630</code>, <code>TotalInquiriesCount = 3</code>, <code>HardInquiriesLast6Months = 1</code>, and <code>OnTimePaymentPercentage = 0.962</code>.</li>
        <li>Additional mock credit-summary values include <code>AverageAccountAgeMonths = 62</code>, <code>AverageAccountAgeYears = 5.17</code>, <code>MortgageDebt = 0</code>, <code>CreditCardDebt = 2500</code>, and <code>PublicRecordsCount = 0</code>.</li>
      </ul>
    </li>
    <li><strong>Default Values.</strong>
      <ul>
        <li>Static entities <code>BureauProvider</code>, <code>CreditCheckStatus</code>, <code>ApplicantRole</code>, <code>PermissiblePurpose</code>, and <code>InquiryType</code>; the mock payload above acts as the current default response profile.</li>
      </ul>
    </li>
    <li><strong>Customization Points.</strong>
      <ul>
        <li><code>CreditIS_CreditCheck</code> (the public wrapper for the credit-bureau check; wire the mock <code>MockBureau_*</code> calls to the real bureau API).</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Banking Regulatory Integration Services</strong> <span class="layer-tag">(Integration)</span></h4>
  <ul>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li>Mock check types include <code>CIP_IDENTITY_VERIFICATION</code>, <code>SSN_NAME_DOB_MATCH</code>, <code>OFAC_SANCTIONS_SCREENING</code>, <code>MLA_COVERED_BORROWER</code>, <code>PRODUCT_TERMS_COMPLIANCE</code>, and <code>ECOA_DECISION_COMPLIANCE</code>.</li>
        <li>Source constants include <code>KYC_PROVIDER</code>, <code>SSA_ECBSV_MOCK</code>, <code>OFAC_MOCK</code>, <code>DMDC_MLA_MOCK</code>, and <code>REG_B_RULE_ENGINE</code>.</li>
        <li>Compliance outcomes include <code>AssessmentId = "BRC-000001"</code>, <code>OverallStatus = "EligibleWithRestrictions"</code>, <code>RecommendedAction = "ProceedWithModifiedTerms"</code>, <code>CoveredBorrower = True</code>, <code>RestrictionProfile = "MLA"</code>, and restriction code <code>MLA_TERMS_APPLY</code>.</li>
      </ul>
    </li>
    <li><strong>Default Values.</strong>
      <ul>
        <li>Thirteen compliance static entities back the enumerations; the mock regulatory payload above acts as the current default response profile.</li>
      </ul>
    </li>
    <li><strong>Customization Points.</strong>
      <ul>
        <li><code>RegulatoryIS_CheckBorrower</code> (the public wrapper for the regulatory borrower check; wire the mock <code>MockRegulatory_CheckBorrower</code> call to the real regulatory API).</li>
      </ul>
    </li>
  </ul>

  <h4><strong>Banking Core Integration Services</strong> <span class="layer-tag">(Integration)</span></h4>
  <ul>
    <li><strong>Hardwired Values.</strong>
      <ul>
        <li>Mock actions still return built-in sample records; <code>MockBank_CreateAccount</code> returns account number <code>"89641376768"</code> and <code>MockBank_GetAllPolicy</code> returns document <code>"personal-loans-general-terms-and-conditions.pdf"</code>.</li>
        <li>The public wrappers use a fixed normalized failure path raising <code>BankCoreException</code> with the message <code>"The operation is not valid and cannot be executed."</code></li>
      </ul>
    </li>
    <li><strong>Customization Points.</strong>
      <ul>
        <li><code>BankCoreIS_GetAllAccounts</code>.</li>
        <li><code>BankCoreIS_GetAllApplications</code>.</li>
        <li><code>BankCoreIS_GetAllApplicationTasks</code>.</li>
        <li><code>BankCoreIS_GetAllBranches</code>.</li>
        <li><code>BankCoreIS_GetAllCustomers</code>.</li>
        <li><code>BankCoreIS_GetAllCustomerPictures</code>.</li>
        <li><code>BankCoreIS_GetAllEmployees</code>.</li>
        <li><code>BankCoreIS_GetAllEmployeePictures</code>.</li>
        <li><code>BankCoreIS_GetAllJobTitles</code>.</li>
        <li><code>BankCoreIS_GetAllKYCustomer</code>.</li>
        <li><code>BankCoreIS_GetAllOffers</code>.</li>
        <li><code>BankCoreIS_GetAllOfferClauses</code>.</li>
        <li><code>BankCoreIS_GetAllPolicy</code>.</li>
        <li><code>BankCoreIS_GetAllRegions</code>.</li>
        <li><code>BankCoreIS_GetAllTransactions</code>.</li>
      </ul>
    </li>
  </ul>
</section>
<!-- /site:field htmlContent -->

### Integration Pattern
<!-- site:field integrationPattern -->

<!-- /site:field integrationPattern -->

<!-- /DOCS:SECTION -->
