# End-to-End Integration Flow

> The `src/<Module>/…` paths used throughout this document are drawn from a
> representative CG Mobile customer workspace. Your workspace may use different
> module names, but the folder structure (`DS/`, `BO/`, `LO/`, `PR/`, `UI/`)
> and the same DS/BO/LO/PR/UI conventions apply.

## Overview

This document synthesizes all architecture layers into complete end-to-end data flows. It traces how data moves from Salesforce through every layer of the CG Mobile App metadata framework to the user interface and back, demonstrating the full integration of DataSource, Business Object, ListObject, Process, and UI layers.

## Complete Architecture Stack

```
+-------------------------------------------------------------+
|                      Salesforce Cloud                        |
|  Account, Account_Receivable__c, Visit__c, etc.            |
|  (Source of Truth)                                          |
+-----------------------------+-------------------------------+
                              | Sync
                              v
+-------------------------------------------------------------+
|                    Local SQLite Database                     |
|  Synced copy of Salesforce data                            |
|  (Offline capability)                                       |
+-----------------------------+-------------------------------+
                              | Query
                              v
+-------------------------------------------------------------+
|               DataSource Layer (DS)                          |
|  - DsBoAccount_sf.datasource.xml                           |
|  - DsLoAccountReceivables_sf.datasource.xml                |
|  Maps: Salesforce Fields -> DS Attributes                  |
+-----------------------------+-------------------------------+
                              | Load
                              v
+-------------------------------------------------------------+
|          Business Object / ListObject Layer                  |
|  - BoAccount.businessobject.xml                            |
|  - LoAccountReceivables.listobject.xml                     |
|  - LiAccountReceivables.listitem.xml                       |
|  Maps: DS Attributes -> BO/LO Properties                   |
|  Implements: Business Logic (.bl.js files)                 |
+-----------------------------+-------------------------------+
                              | Orchestrate
                              v
+-------------------------------------------------------------+
|                Process Layer (PR)                            |
|  - Call_AccountReceivablesProcess.processflow.xml          |
|  - Visit_InfoProcess.processflow.xml                       |
|  Coordinates: Load, Execute Logic, Navigate                |
|  Stores: ProcessContext variables                          |
+-----------------------------+-------------------------------+
                              | Bind
                              v
+-------------------------------------------------------------+
|              User Interface Layer (UI)                       |
|  - Call_AccountReceivablesUI.userinterface.xml             |
|  - Visit_InfoUI.userinterface.xml                          |
|  Binds: ProcessContext -> UI Controls                      |
|  Renders: Responsive layouts (Phone/Tablet/Desktop)        |
+-----------------------------+-------------------------------+
                              | Display
                              v
+-------------------------------------------------------------+
|                           User                               |
|  Views and interacts with mobile app                        |
+-------------------------------------------------------------+
```

## End-to-End Flow 1: Display Account Receivables List

### Scenario

User opens Account Receivables screen to view outstanding invoices for a customer.

### Step 1: Salesforce Data (Source)

**Salesforce Object:** `Account_Receivable__c`

**Sample Query:**

```sql
SELECT Id, External_Id__c, Document_Type__c, Receipt_Date__c, Due_Date__c,
       Amount__c, Amount_Open__c, Invoice_Status__c, Account__c
FROM Account_Receivable__c
WHERE Account__c = '001O300001TYlYFIA1'
ORDER BY Receipt_Date__c ASC
```

**Results:**
| Id | External_Id**c | Document_Type**c | Receipt_Date**c | Due_Date**c | Amount**c | Amount_Open**c | Invoice_Status\_\_c |
|----|----------------|------------------|-----------------|-------------|-----------|----------------|-------------------|
| a01xxx | INV-1001 | Invoice | 2026-01-15 | 2026-02-15 | 1000.00 | 500.00 | PartiallyPaid |
| a01yyy | INV-1002 | Invoice | 2026-01-20 | 2026-02-20 | 750.00 | 750.00 | UnPaid |
| a01zzz | CN-1003 | Credit Note | 2026-01-25 | 2026-02-25 | -200.00 | 0.00 | Paid |

### Step 2: Sync to SQLite

-   **Mechanism:** Salesforce Mobile SDK sync
-   **Frequency:** Background sync (configurable)
-   **Storage:** Local SQLite database
-   **Result:** Data available offline

### Step 3: DataSource Query

**File:** `src/Call/DS/DsLoAccountReceivables_sf.datasource.xml`

```xml
<DataSource name="DsLoAccountReceivables" backendSystem="sf" readOnly="true">
  <Attributes>
    <Attribute name="pKey" table="Account_Receivable__c" column="Id" />
    <Attribute name="externalId" table="Account_Receivable__c" column="External_Id__c" />
    <Attribute name="documentType" table="Account_Receivable__c" column="Document_Type__c" />
    <Attribute name="receiptDate" table="Account_Receivable__c" column="Receipt_Date__c" />
    <Attribute name="dueDate" table="Account_Receivable__c" column="Due_Date__c" />
    <Attribute name="amount" table="Account_Receivable__c" column="Amount__c" />
    <Attribute name="amountOpen" table="Account_Receivable__c" column="Amount_Open__c" />
    <Attribute name="invoiceStatus" table="Account_Receivable__c" column="Invoice_Status__c" />
  </Attributes>
  <QueryCondition><![CDATA[
    Account_Receivable__c.Account__c = #customerPKey#
  ]]></QueryCondition>
  <OrderCriteria>
    <OrderCriterion entity="Account_Receivable__c" attribute="Receipt_Date__c" direction="ASC" />
  </OrderCriteria>
</DataSource>
```

### Step 4: ListObject Loading

**File:** `src/Call/BO/LoAccountReceivables/LoAccountReceivables.listobject.xml`

```javascript
// Loading Process:
// 1. Execute datasource query with parameters
// 2. For each result record:
//    a. Create LiAccountReceivables instance
//    b. Map DS attributes to Li properties
//    c. Add item to list
// 3. Call afterLoadAsync()
```

### Step 5: Business Logic

**File:** `src/Call/BO/LoAccountReceivables/Mv2/LoAccountReceivables.CalculateAccountReceivablesForCard.bl.js`

```javascript
function calculateAccountReceivablesForCard(customerPKey) {
    var me = this;
    var currentDate = Utils.createAnsiDateToday();

    return BoFactory.loadObjectByParamsAsync('LoAccountReceivables', jsonQuery).then(function (loAccountReceivables) {
        var receivablesRelevantAccount = loAccountReceivables.getAllItems();

        receivablesRelevantAccount.forEach(function (accountRecievables) {
            // Set icon based on due date and status
            if (accountRecievables.getDueDate() < currentDate && accountRecievables.getInvoiceStatus() === 'UnPaid') {
                accountRecievables.setAccountReceivableIcon('WarningTriangle_IC');
            } else if (
                accountRecievables.getDueDate() < currentDate &&
                accountRecievables.getInvoiceStatus() === 'PartiallyPaid'
            ) {
                accountRecievables.setAccountReceivableIcon('WarningCircle_IC');
            }

            // Localize dates
            var localizedDueDate = Localization.localize(accountRecievables.getDueDate(), 'date');
            accountRecievables.setDueDateText(localizedDueDate);

            // Combine external ID and document type
            accountRecievables.setExternalIdInvoiceInfo(accountRecievables.getExternalId() + ' - ' + documentTypeText);
        });

        me.removeAllItems();
        me.addItems(relevantAccountReceivables);
    });
}
```

### Step 6: Process Orchestration

**File:** `src/Call/PR/Call_AccountReceivables/Call_AccountReceivablesProcess.processflow.xml`

```xml
<Process name="Call::AccountReceivablesProcess" defaultAction="ShowView">
  <Entry>
    <ProcessContext>
      <Parameters>
        <Input name="AccountReceivableList" type="LoAccountReceivables" />
      </Parameters>
    </ProcessContext>
    <EntryActions/>
  </Entry>
  <Body>
    <Actions>
      <Action actionType="VIEW" name="ShowView">
        <UIDescription>Call::AccountReceivablesUI</UIDescription>
      </Action>
    </Actions>
  </Body>
</Process>
```

### Step 7: UI Rendering

**Binding Resolution:**

```
dataSource="ProcessContext::AccountReceivableList"
    |
UI iterates through list.getAllItems()
    |
For each item (LiAccountReceivables):
    binding=".amount" -> item.getAmount() -> 1000.00
    binding=".amountOpen" -> item.getAmountOpen() -> 500.00
    binding=".accountReceivableIcon" -> item.getAccountReceivableIcon() -> "WarningTriangle_IC"
    binding=".externalIdInvoiceInfo" -> item.getExternalIdInvoiceInfo() -> "INV-1001 - Invoice"
    binding=".dueDateText" -> item.getDueDateText() -> "Feb 15, 2026"
    |
Apply format:
    formatV2="10.2" -> 1000.00 displays as "1,000.00"
```

### Complete Mapping Chain

```
Salesforce Field          -> DS Attribute    -> LO Property         -> Computed Property           -> UI Binding              -> Display
------------------------------------------------------------------------------------------------------------------------------
Account_Receivable__c.Id  -> pKey            -> pKey (DomPKey)      ->                             -> (not displayed)          -> (internal)
External_Id__c            -> externalId      -> externalId          -> externalIdInvoiceInfo       -> .externalIdInvoiceInfo   -> "INV-1001 - Invoice"
Document_Type__c          -> documentType    -> documentType        -> (part of combined)          ->                          -> (combined)
Due_Date__c               -> dueDate         -> dueDate (DomDate)   -> dueDateText (localized)     -> .dueDateText             -> "Feb 15, 2026"
Amount__c                 -> amount          -> amount (DomMoney)   ->                             -> .amount (format 10.2)    -> "1,000.00"
Amount_Open__c            -> amountOpen      -> amountOpen          ->                             -> .amountOpen              -> "500.00"
Invoice_Status__c         -> invoiceStatus   -> invoiceStatus       -> (used for icon logic)       ->                          -> (used for icon)
(computed)                ->                 ->                     -> accountReceivableIcon       -> .accountReceivableIcon   -> warning icon
```

## End-to-End Flow 2: Edit and Save Visit Information

### Scenario

User reschedules a visit to a different date and time.

### Step 1: Load Visit Data

```xml
<Action name="LoadVisit" actionType="LOAD" type="BoWizardRescheduleVisit">
  <Parameters>
    <Input name="pKey" value="ProcessContext::VisitPKey" />
  </Parameters>
  <Return name="ProcessContext::RescheduleVisitBo" />
</Action>
```

**BO Load:**

```
1. Execute datasource query
2. DS attributes -> BO properties:
   - pKey = "V01xxx"
   - dateFrom = "2026-02-18"
   - timeFrom = "09:00"
   - dateThru = "2026-02-18"
   - timeThru = "10:00"
   - duration = 60
3. BO stored in ProcessContext::RescheduleVisitBo
```

### Step 2: Display UI with TWO_WAY Bindings

```xml
<DatePickerField name="VisitStartDate">
  <Bindings>
    <Binding target="Value" binding="ProcessContext::RescheduleVisitBo.dateFrom" bindingMode="TWO_WAY" />
  </Bindings>
</DatePickerField>
<TimePickerField name="TimeFrom">
  <Bindings>
    <Binding target="Value" binding="ProcessContext::RescheduleVisitBo.timeFrom" bindingMode="TWO_WAY" />
  </Bindings>
</TimePickerField>
```

### Step 3: User Edits

**TWO_WAY binding writes:**

```
User changes date picker to 02/19/2026
    -> ProcessContext.RescheduleVisitBo.setDateFrom("2026-02-19")

User changes time picker to 10:00
    -> ProcessContext.RescheduleVisitBo.setTimeFrom("10:00")
```

### Step 4: User Saves (Button Event)

```xml
<Action name="HandleReschedule" actionType="LOGIC" call="ProcessContext::VisitBo.reschedule">
  <Parameters>
    <Input name="newDateFrom" value="ProcessContext::RescheduleVisitBo.dateFrom" />
    <Input name="newTimeFrom" value="ProcessContext::RescheduleVisitBo.timeFrom" />
    <Input name="newDateThru" value="ProcessContext::RescheduleVisitBo.dateThru" />
    <Input name="newTimeThru" value="ProcessContext::RescheduleVisitBo.timeThru" />
  </Parameters>
  <TransitionTo action="SaveVisit" />
</Action>
```

### Step 5: Business Logic Execution

```javascript
function reschedule(newDateFrom, newTimeFrom, newDateThru, newTimeThru){
    var me = this;

    var timeFrom = Utils.convertAnsiDate2Date(newDateFrom);
    timeFrom.setHours(newTimeFrom.substring(0,2));
    timeFrom.setMinutes(newTimeFrom.substring(3,5));

    // Calculate end time from duration
    var timeDifference = me.getCallDuration(...);
    var timeThru = new Date(timeFrom);
    timeThru.setMinutes(timeFrom.getMinutes() + timeDifference);

    // Validate start before end
    if (timeThru.toJSON() <= timeFrom.toJSON()) {
        logMsg("Start DateTime must be before End DateTime");
        return;
    }

    me.setPlannedStartDate(timeFrom);
    me.setPlannedStartTime(Utils.convertTime2Ansi(timeFrom));
    me.setPlannedEndDate(timeThru);
    me.setPlannedEndTime(Utils.convertTime2Ansi(timeThru));
}
```

### Step 6: Save to Database

```
1. BoVisit.saveAsync() triggered
2. beforeSaveAsync() executes (preprocessing)
3. DsBoVisit writes to SQLite
4. afterSaveAsync() executes (postprocessing)
5. Changes marked for sync to Salesforce
```

### Step 7: Sync to Salesforce

```
SQLite dirty records queued
    |
Salesforce Mobile SDK sync process
    |
REST API call to Salesforce:
    PATCH /services/data/vXX.0/sobjects/Visit__c/V01xxx
    {
      "Planned_Start_Date__c": "2026-02-19",
      "Planned_Start_Time__c": "10:00",
      "Planned_End_Date__c": "2026-02-19",
      "Planned_End_Time__c": "11:00",
      "Duration__c": 60
    }
    |
Salesforce record updated
```

## Common Integration Patterns

### Pattern 1: Read-Only Display

**Use Case:** Show information, no edits

**Flow:**

```
Salesforce -> DS -> BO/LO -> Process (LOAD) -> ProcessContext -> UI (ONE_WAY) -> Display
```

**Key Points:**

-   ONE_WAY bindings
-   disabled="true" on controls
-   No save process actions

### Pattern 2: Edit and Save

**Use Case:** User modifies data

**Flow:**

```
Salesforce -> DS -> BO -> Process (LOAD) -> ProcessContext -> UI (TWO_WAY) -> Edit
                                                                                 |
Salesforce <- DS <- BO <- Process (SAVE) <- ProcessContext <- UI (TWO_WAY) <- Save Button Event
```

**Key Points:**

-   TWO_WAY bindings
-   Menu item with event
-   VALIDATION action before SAVE
-   Business logic in BO methods

### Pattern 3: List with Computed Properties

**Use Case:** Display list with calculated values

**Flow:**

```
Salesforce (multiple records) -> DS -> LO -> afterLoadAsync() computes properties -> Process -> UI -> List Display
```

**Key Points:**

-   ListObject with ListItem
-   Computed properties set in afterLoadAsync()
-   GroupedList control with ItemListLayout
-   Responsive layouts (Phone/Tablet/Default)

### Pattern 4: Master-Detail Navigation

**Use Case:** List -> Detail drill-down

**Flow:**

```
List Screen (LO) -> User selects item -> ItemSelectedEvent -> Process handles event -> Navigate to detail -> Load BO -> Detail Screen
```

### Pattern 5: Parent-Child Data

**Use Case:** Load parent with children

**Flow:**

```
Process EntryActions:
    1. LOAD BoParent
    2. LOGIC call BoParent.getLoChildren().loadAsync()
    3. Both available in ProcessContext
UI binds to both:
    - ProcessContext::ParentBo.name
    - ProcessContext::ParentBo.loChildren (list)
```

### Pattern 6: Lazy Loading (Cockpit Cards)

**Use Case:** Load card data only when visible

**Flow:**

```
1. EntryActions: CREATE empty ListObjects (no data loaded)
2. UI Card scrolled into view -> Triggers CardLoadEvent
3. Process Event Handler: Sets DataLoaded flag, transitions to load action
4. Load Action: Calls LO custom method with parameters
5. LO Method: Queries SQLite via DS, filters/aggregates, populates items
6. UI Re-Render: Bindings refresh, displays populated data
```

**Benefit:** Initial load time minimized, only visible cards load data.

## Data Synchronization

### Offline-First Architecture

```
Mobile App (SQLite)  <->  Salesforce Cloud
    |                        |
Local CRUD ops          Source of truth
Immediate response      Eventually consistent
Offline capable         Online required
```

### Sync Mechanism

**Download (Salesforce -> SQLite):**

1. Salesforce Mobile SDK queries Salesforce
2. Downloads records based on sync configuration
3. Stores in local SQLite database
4. App queries SQLite (not Salesforce directly)

**Upload (SQLite -> Salesforce):**

1. User modifies data
2. BO.saveAsync() writes to SQLite
3. Record marked as "dirty" (needs sync)
4. Background sync process uploads dirty records
5. Salesforce updated via REST API
6. Local record marked as clean

### Conflict Resolution

-   Last-write-wins (default)
-   Custom conflict handlers in BO logic
-   Version field checks (Modified_Date\_\_c)

## Performance Considerations

### DataSource Optimization

**Good:**

```xml
<!-- Load only needed fields -->
<Attribute name="name" column="Name" />
<Attribute name="status" column="Status__c" />

<!-- Filter at query level -->
<QueryCondition>Status__c = 'Active'</QueryCondition>
```

**Bad:**

```xml
<!-- Load all fields (slow) -->
<!-- Filter in JavaScript (inefficient) -->
items.filter(i => i.status === 'Active')
```

### Process Loading

**Good:** Load in EntryActions (before UI displays)
**Bad:** Load in Body after VIEW action (UI waits)

### UI Rendering

**Good:** Use ONE_WAY for read-only (faster than TWO_WAY)
**Bad:** TWO_WAY on disabled fields (unnecessary overhead)

## Error Handling Patterns

### Validation Errors

```
User saves -> VALIDATION action -> BO.afterDoValidateAsync() ->
messageCollector.add({level: "error"}) ->
ValidationResult.valid = false ->
Process DECISION -> Show error screen
```

### Business Logic Errors

```javascript
function reschedule(newDate) {
    if (!validateDate(newDate)) {
        AppLog.error('Invalid date provided');
        return; // Early exit
    }
}
```

### Network Errors (Sync Failures)

-   Queued for retry
-   Error logged
-   User notification (optional)

## Verified Pattern Summary

| Layer | Pattern                              | Description                                 |
| ----- | ------------------------------------ | ------------------------------------------- |
| DS    | Attribute -> SF Field Mapping        | Maps Salesforce columns to DS attributes    |
| DS    | Query Conditions with Parameters     | Dynamic filtering via `#paramName#`         |
| DS    | Entity Joins                         | Multiple tables in single query             |
| DS    | DateTimeAttribute Split              | Single DateTime -> separate Date + Time     |
| DS    | DerivedAttribute Defaults            | Default values for computed DS attributes   |
| BO    | SimpleProperty Mapping               | DS attributes to BO properties              |
| BO    | Custom Domain Types                  | Typed values (DomVisitStatus, DomMoney)     |
| BO    | Lifecycle Methods                    | before/after hooks for CRUD                 |
| BO    | Custom Methods                       | Entity-specific operations                  |
| BO    | Child ListObject Relationships       | BO contains child LO                        |
| BO    | Computed Properties                  | Derived from persisted props in BL          |
| BO    | ACL Pattern for Protected Properties | Temp grant EDIT to modify protected fields  |
| BO    | Computed UI Properties               | Separate data vs display properties         |
| LO    | Collection Operations                | getAllItems, addItems, removeAllItems       |
| LO    | Custom Aggregation Methods           | Calculate totals, counts, summaries         |
| LO    | Device-Aware Data Limits             | Different item counts for phone vs tablet   |
| LO    | Information Text Pattern             | "X / Y" summaries for cards                 |
| Lu    | SQL Aggregate Queries                | COUNT, SUM lookups for dashboards           |
| PR    | EntryActions Pre-Load                | Load data before UI displays                |
| PR    | LOAD/SAVE/LOGIC/DECISION Actions     | Core action types                           |
| PR    | ProcessContext Storage               | Variables accessible across process         |
| PR    | Chained LOAD Actions                 | Load A, then use A's data to load B         |
| PR    | Lazy Loading Pattern                 | Load data only when UI card visible         |
| PR    | Card Controller Pattern              | Centralized visibility/refresh control      |
| PR    | Cascading Refresh                    | One change refreshes multiple related cards |
| UI    | Bindings to ProcessContext           | Connect UI controls to data                 |
| UI    | ONE_WAY/TWO_WAY Binding Modes        | Read-only vs editable                       |
| UI    | Responsive Layouts                   | Phone/Tablet/Desktop adaptations            |
| UI    | Chart Component Binding              | Data-driven chart visualization             |
| UI    | Card Load Events                     | Trigger data loading on visibility          |

## Complete Layer Integration Summary

| Layer               | Responsibility     | Input          | Output                   |
| ------------------- | ------------------ | -------------- | ------------------------ |
| **Salesforce**      | Source of truth    | User/API       | Data records             |
| **Sync**            | Offline capability | SF records     | SQLite records           |
| **DataSource**      | Data mapping       | SF fields      | DS attributes            |
| **Business Object** | Business logic     | DS attributes  | BO properties + methods  |
| **ListObject**      | Collection mgmt    | DS attributes  | LO items + methods       |
| **Process**         | Orchestration      | Parameters     | ProcessContext variables |
| **UI**              | Presentation       | ProcessContext | Screen display           |
| **User**            | Interaction        | Display        | Input events             |

## End-to-End Checklist

When implementing a new feature, ensure:

-   [ ] **Salesforce object** exists with required fields
-   [ ] **DataSource** maps SF fields to DS attributes
-   [ ] **BO/LO definition** maps DS attributes to properties
-   [ ] **Business logic** implements rules in .bl.js files
-   [ ] **Process** loads BOs/LOs and handles events
-   [ ] **UI bindings** connect to ProcessContext variables
-   [ ] **Responsive layouts** defined for Phone/Tablet/Default
-   [ ] **Localization** added for all labels
-   [ ] **Validation** implemented in BO methods
-   [ ] **Error handling** covers edge cases
-   [ ] **Tests** cover business logic

---

_This documentation is maintained by the Modeler CLI plugin and refreshed on workspace upgrade._
