Back to skills
SKILL.md
089 Triangle 52e4b45b
ASecurityThe **Triangle Architecture** is a foundational Salesforce pattern where Flow, LWC, and Apex work together. This guide focuses on the **Apex role** in this architecture. ---
- 9 stars
- 0 votes
- 0 copies
- 1 view
- Added October 11, 2026
Security analysis
100/100npx -y skills add tools-only/X-Skills --skill 089-triangle_52e4b45b --agent claude-codeAre you the author of 089 Triangle 52e4b45b?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/tools-only-089-triangle-52e4b45b)# Flow-LWC-Apex Triangle: Apex Perspective
The **Triangle Architecture** is a foundational Salesforce pattern where Flow, LWC, and Apex work together. This guide focuses on the **Apex role** in this architecture.
---
## Architecture Overview
```
┌─────────────────────────────────────┐
│ FLOW │
│ (Orchestrator) │
└───────────────┬─────────────────────┘
│
┌──────────────────────────┼──────────────────────────┐
│ │ │
│ screens │ actionCalls │
│ <componentInstance> │ actionType="apex" │
│ │ │
▼ ▼ ▲
┌─────────────────────────┐ ┌─────────────────────────┐ │
│ LWC │ │ APEX │ │
│ (UI Component) │───▶│ (Business Logic) │─────────┘
│ │ │ │
│ • Rich UI/UX │ │ • @InvocableMethod ◀── YOU ARE HERE
│ • User Interaction │ │ • @AuraEnabled │
│ │ │ • Complex Logic │
│ │ │ • DML Operations │
│ │ │ • Integration │
└─────────────────────────┘ └─────────────────────────┘
│ ▲
│ @AuraEnabled │
│ wire / imperative │
└──────────────────────────┘
```
---
## Apex's Role in the Triangle
| Communication Path | Apex Annotation | Direction |
|-------------------|-----------------|-----------|
| Flow → Apex | `@InvocableMethod` | Request/Response |
| Apex → Flow | `@InvocableVariable` | Return values |
| LWC → Apex | `@AuraEnabled` | Async call |
| Apex → LWC | Return value | Response |
---
## Pattern 1: @InvocableMethod for Flow
**Use Case**: Complex business logic, DML, or external integrations called from Flow.
```
┌─────────┐ actionCalls ┌─────────┐
│ FLOW │ ───────────────▶ │ APEX │
│ Auto- │ List<Request> │Invocable│
│ mation │ ◀─────────────── │ Method │
│ │ List<Response> │ │
└─────────┘ └─────────┘
```
### Apex Class Pattern
```apex
public with sharing class RecordProcessor {
@InvocableMethod(label='Process Record' category='Custom')
public static List<Response> execute(List<Request> requests) {
List<Response> responses = new List<Response>();
for (Request req : requests) {
Response res = new Response();
try {
// Business logic here
res.isSuccess = true;
res.processedId = req.recordId;
} catch (Exception e) {
res.isSuccess = false;
res.errorMessage = e.getMessage();
}
responses.add(res);
}
return responses;
}
public class Request {
@InvocableVariable(required=true)
public Id recordId;
}
public class Response {
@InvocableVariable
public Boolean isSuccess;
@InvocableVariable
public Id processedId;
@InvocableVariable
public String errorMessage;
}
}
```
### Corresponding Flow XML
```xml
<actionCalls>
<name>Process_Records</name>
<actionName>RecordProcessor</actionName>
<actionType>apex</actionType>
<inputParameters>
<name>recordId</name>
<value><elementReference>var_RecordId</elementReference></value>
</inputParameters>
<outputParameters>
<assignToReference>var_IsSuccess</assignToReference>
<name>isSuccess</name>
</outputParameters>
<faultConnector>
<targetReference>Handle_Error</targetReference>
</faultConnector>
</actionCalls>
```
---
## Pattern 2: @AuraEnabled for LWC
**Use Case**: LWC needs data or operations beyond Flow context.
```
┌─────────┐ @wire ┌─────────┐
│ LWC │ ────────────────▶ │ APEX │
│ │ imperative │@Aura │
│ │ ◀──────────────── │Enabled │
│ │ Promise/data │ │
└─────────┘ └─────────┘
```
### Apex Controller
```apex
public with sharing class RecordController {
@AuraEnabled(cacheable=true)
public static List<Record__c> getRecords(Id parentId) {
return [
SELECT Id, Name, Status__c
FROM Record__c
WHERE Parent__c = :parentId
WITH USER_MODE
];
}
@AuraEnabled
public static Map<String, Object> processRecord(Id recordId) {
// Process logic (DML operations)
return new Map<String, Object>{
'isSuccess' => true,
'recordId' => recordId
};
}
}
```
### Key Differences
| Annotation | Cacheable | Use For |
|------------|-----------|---------|
| `@AuraEnabled(cacheable=true)` | Yes | Read-only queries (SOQL) |
| `@AuraEnabled` | No | DML operations, mutations |
---
## Testing @InvocableMethod
```apex
@isTest
private class RecordProcessorTest {
@isTest
static void testProcessRecords() {
Account acc = new Account(Name = 'Test');
insert acc;
RecordProcessor.Request req = new RecordProcessor.Request();
req.recordId = acc.Id;
Test.startTest();
List<RecordProcessor.Response> responses =
RecordProcessor.execute(new List<RecordProcessor.Request>{ req });
Test.stopTest();
System.assertEquals(true, responses[0].isSuccess);
System.assertEquals(acc.Id, responses[0].processedId);
}
@isTest
static void testBulkProcessing() {
// Test with 200+ records for bulkification
List<Account> accounts = new List<Account>();
for (Integer i = 0; i < 251; i++) {
accounts.add(new Account(Name = 'Test ' + i));
}
insert accounts;
List<RecordProcessor.Request> requests = new List<RecordProcessor.Request>();
for (Account acc : accounts) {
RecordProcessor.Request req = new RecordProcessor.Request();
req.recordId = acc.Id;
requests.add(req);
}
Test.startTest();
List<RecordProcessor.Response> responses = RecordProcessor.execute(requests);
Test.stopTest();
System.assertEquals(251, responses.size());
}
}
```
---
## Deployment Order
When deploying integrated triangle solutions:
```
1. APEX CLASSES ← Deploy FIRST
└── @InvocableMethod classes
└── @AuraEnabled controllers
2. LWC COMPONENTS
└── Depend on Apex controllers
3. FLOWS
└── Reference deployed Apex classes
└── Reference deployed LWC components
```
---
## Common Anti-Patterns
| Anti-Pattern | Problem | Solution |
|--------------|---------|----------|
| Non-bulkified Invocable | Fails for multi-record Flows | Use `List<Request>` → `List<Response>` |
| Missing faultConnector handling | Exceptions crash Flow | Return error in Response, add fault path |
| Cacheable method with DML | Runtime error | Remove `cacheable=true` for mutations |
| Mixing concerns | Hard to test | Separate controller (LWC) from service (Flow) classes |
---
## Decision Matrix
| Scenario | Use @InvocableMethod | Use @AuraEnabled |
|----------|---------------------|------------------|
| Called from Flow | ✅ | ❌ |
| Called from LWC | ❌ | ✅ |
| Needs bulkification | ✅ (always bulk) | Optional |
| Read-only query | Either | ✅ (cacheable) |
| DML operations | ✅ | ✅ |
| External callout | ✅ | ✅ |
---
## Related Documentation
| Topic | Location |
|-------|----------|
| @InvocableMethod templates | `sf-apex/templates/invocable-method.cls` |
| Flow integration guide | `sf-apex/docs/flow-integration.md` |
| LWC triangle perspective | `sf-lwc/docs/triangle-pattern.md` |
| Flow triangle perspective | `sf-flow/docs/triangle-pattern.md` |
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.