Salesforce Flow 현대화은(는) 무엇을 하나요?
이 스킬은 AI 모델의 학습 데이터에서 기본적으로 사용되는 'Loop + Decision + Assignment + DML inside loops + after-save updates' 패턴을 최신 엘리먼트로 대체합니다. 각 엘리먼트에 대한 배포 검증된 메타데이터는 examples/ 디렉토리에서 확인할 수 있습니다.
다음 규칙이 대부분의 결정을 좌우합니다.
- 최신 엘리먼트가 기본값입니다. Loop를 사용하려면 명시된 이스케이프 조건(아래 참조)이 있어야 합니다. 엘리먼트의 XML이 익숙하지 않으면, 해당 엘리먼트를 회피하는 대신 예제 파일에서 형태를 복사하십시오.
- 검증 불가능이 사용 불가능을 의미하지는 않습니다. 사용 가능 여부는 조직의 API 버전과 아래 테이블에 따릅니다. 최소 요구 버전이 조직 버전 이하인 엘리먼트를 사용하기 위해 웹 액세스가 필요하지는 않습니다. 실제 확인은 배포 검증(Deploy Validation)입니다.
- 모든 Loop와 모든 대체(Fallback)에는 이유가 명시되어야 합니다. Loop의 설명(description)과 인도물(Deliverable)에 이스케이프 사유를 명명하십시오. 명명된 이스케이프가 없으면 Loop를 작성하지 마십시오.
워크플로우
다음 체크리스트를 작업 노트에 복사하고 완료 시 체크하십시오:
- [ ] 1. references/org-conventions.md 읽기; 이 작업이 의존하는 설정되지 않은 슬롯 나열
- [ ] 2. 조직 API 버전 확인
- [ ] 3. 작업 분류: 빌드, 감사 또는 마이그레이션; Flow 유형, 트리거 이벤트, 실행 주체
- [ ] 4. 의사 결정 테이블을 통해 모든 요구사항 매핑; 사용할 각 예제 열기
- [ ] 5. 메타데이터(또는 빌드 스펙) 작성
- [ ] 6. scripts/check-flow.mjs 실행; 모든 ERROR 수정, 모든 WARNING에 대해 결정
- [ ] 7. 조직을 사용할 수 있으면 배포 검증; 그렇지 않으면 XML에 '검증되지 않음' 레이블 지정
- [ ] 8. references/delivery.md의 리뷰 체크리스트 실행 후 인도
1단계: 규칙. org-conventions.md에 채워진 슬롯이 이 스킬의 기본값보다 우선합니다. 빈 슬롯은 기본값이 적용되며, 인도물에 열린 결정(Open Decision)으로 나열됩니다.
2단계: API 버전. 조직이 있는 경우, sf org display --target-org <alias> 명령어로 "Api Version"을 확인합니다. 조직이 없는 경우, 프로젝트의 sfdx-project.json에 있는 sourceApiVersion을 사용하거나, 이것도 없을 경우 67.0을 사용하며 그 사실을 명시합니다. 새 Flow의 apiVersion은 해당 버전으로 설정합니다.
3단계: 분류. 기존 Flow인지 새 빌드인지 확인합니다. Flow 유형(화면, 레코드 트리거(저장 전/저장 후), 자동 실행, 예약 트리거, 플랫폼 이벤트 트리거). 트리거 대상 오브젝트 및 트리거 이벤트는 예제를 열기 전에 요구사항에서 확인합니다. 핵심 질문은 조건을 이미 충족하는 레코드가 생성될 때도 카운트되는지, 아니면 조건으로 변경될 때만 카운트되는지입니다. "업데이트 시 조건 충족 시에만"은 생성 시에 실행되지만, 업데이트 전용은 그렇지 않습니다(record-triggered.md). 실행 주체(사용자, 시스템, 에이전트). 동기적으로 처리되어야 하는 작업. 화면 Flow의 경우, 이를 임베드하는 표면과 입력/반환 값을 확인합니다.
4단계: 매핑. 각 컬렉션 작업, 선택 목록, 화면 상호 작용, 레코드 업데이트, 타이밍 필요성 및 통합에 대해 의사 결정 테이블에서 해당 행을 가져옵니다. 작성할 모든 엘리먼트의 예제 파일과 해당 도메인의 한계에 대한 참조를 읽습니다. 작업과 관련된 도메인의 참조만 읽습니다.
5단계: 작성. 메타데이터는 force-app/main/default/flows/<ApiName>.flow-meta.xml에 배치합니다(프로젝트의 패키지 디렉터리에 맞게 조정). 명명 기본값: Flow API 이름은 Object_Verb_Condition, 엘리먼트 이름은 Type_Purpose(예: Get_Open_Cases, Filter_High_Priority, Transform_To_Tasks, Dec_Is_Renewal)를 사용하며, org-conventions.md에 다른 규칙이 명시된 경우는 예외입니다. 사용자가 명시적으로 활성 Flow를 요청하거나 Activation-Policy 슬롯이 그렇게 지정하지 않는 한 <status>Draft</status>로 설정합니다. 예제들은 실행되었기 때문에 Active 상태입니다. 동일한 유형의 모든 엘리먼트는 파일 내에서 함께 유지해야 합니다(분할 그룹은 배포 실패). CLI 액세스가 없는 경우, delivery.md 형식의 빌드 스펙을 인도합니다.
6단계: 검사. 작성했거나 검토 요청받은 모든 Flow에 대해 체커를 실행합니다. Node만 필요합니다:
node <skill-dir>/scripts/check-flow.mjs --api <org-api-version> force-app/main/default/flows/<ApiName>.flow-meta.xml
ERROR는 레거시 패턴이거나 플랫폼에서 거부하는 형태이므로 수정해야 합니다. WARNING은 결정이 필요하며, 그 결정을 인도물에 명시합니다.
7단계: 검증. 인증된 조직이 있는 경우, CLI의 기본 조직에 의존하지 않고 조직을 명시적으로 지정합니다:
sf project deploy validate --source-dir force-app/main/default/flows/<ApiName>.flow-meta.xml --target-org <alias>
정확한 오류 메시지에 따라 수정하고 다시 실행합니다. 검증되지 않은 XML은 인도물에 '검증되지 않음(Unvalidated)'으로 명확히 레이블을 지정합니다.
8단계: 리뷰 및 인도. delivery.md의 리뷰 체크리스트를 실행합니다. 인도물을 다음 블록으로 끝내며, 모든 줄을 채웁니다:
모드: metadata | build spec
체커: <command> → <n> errors, <n> warnings (<decision per warning>)
배포 검증: <command and result> | not run, unvalidated (<reason>)
상태: Draft | Active (<why>)
실행 컨텍스트: <runInMode or default, and what that means for this flow type>
이스케이프: <E-id and reason per loop or fallback> | none
열린 결정: <unset convention slots this flow depends on> | none
실행 컨텍스트 기본값(runInMode DefaultMode): 레코드 트리거, 예약 트리거 및 플랫폼 이벤트 트리거 Flow는 공유 없이 시스템 컨텍스트에서 실행됩니다. 화면 및 자동 실행 Flow는 UI 또는 REST API에서 시작되면 사용자 컨텍스트에서 실행되고, Apex 또는 다른 Flow에서 호출되면 호출자의 컨텍스트에서 실행됩니다. 자동 실행은 "기본적으로 시스템"이 아닙니다.
감사 및 마이그레이션
기존 Flow의 경우, 먼저 체커를 실행한 후, 의사 결정 테이블의 마지막 열을 기준으로 남은 레거시 패턴을 목록화합니다. 재작성 전에 delivery.md에 정의된 감사 보고서를 영향 순서(Governor Limit > 보안 컨텍스트 > 사용자 경험)로 인도합니다. 요청받지 않는 한 Flow를 수정하지 마십시오. 요청받은 경우, 보고서의 마이그레이션 계획을 순서대로 따르십시오. 패턴을 설명하고, 이를 만든 사람을 설명하지 마십시오. 대부분의 레거시 패턴은 작성 당시 권장되는 접근 방식이었기 때문입니다. Process Builder 및 워크플로우 규칙 매핑은 legacy-migration.md에 있습니다.
의사 결정 테이블
"Org API"는 엘리먼트를 사용할 수 있는 최소 조직 API 버전입니다(Flow, Metadata API Developer Guide). 예제는 examples/flows/에 있으며, API 67.0에서 배포 및 실행되었습니다.
| 요구사항 | 사용 | 메타데이터 | Org API | 예제 | 대체 대상 |
|---|---|---|---|---|---|
| 컬렉션 항목을 조건에 따라 유지 | Collection Filter (conditions or formula) | collectionProcessors, FilterCollectionProcessor | 53 | Opportunity_Create_Followup_Tasks | Loop + Decision + Assignment |
| 컬렉션에서 레코드 빌드, 필드 재구성 | Transform, Map | transforms | 59 | Opportunity_Create_Followup_Tasks | Loop + Assignment building a collection |
| 컬렉션 합계 또는 개수 | Transform, Sum / Count. 저장 전 Flow에서는 Filter + Assignment AssignCount, 또는 Loop for Sum (E3) | transforms, inputParameters | 59 (primitive target 62) | Opportunity_Create_Followup_Tasks, Account_Before_Save_Count_Contacts | Loop counters |
| 키를 기준으로 두 컬렉션 결합 | Transform, InnerJoin, with the mapping in the same Transform | transforms, JoinDefinition | 63 | Opportunity_Create_Account_Tasks_Joined | Nested loops, Get Records inside a loop |
| 컬렉션 정렬 | Collection Sort (sorts in place) | SortCollectionProcessor | 50 | Opportunity_Allocate_Budget_Waterfall | Manual sorting in a loop |
| 여러 레코드 생성, 업데이트 또는 삭제 | 준비된 컬렉션에 대한 하나의 DML | recordCreates inputReference | any | Opportunity_Create_Followup_Tasks | DML inside a loop |
| 레코드 또는 선택 목록의 옵션 | Record / picklist choice set | dynamicChoiceSets | any | Account_Order_Entry_Screen | Get Records + Loop building choices |
| 입력에 따라 변하는 합계, 표시 여부 또는 텍스트 | Reactive formula, visibilityRule | formulas, screen fields | 59 | Account_Order_Entry_Screen | 재계산을 위한 두 번째 화면 |
| 화면의 입력 규칙 | Component validationRule | screen fields | any | Account_Order_Entry_Screen | 화면 후 Decision -> 에러 화면으로 돌아가기 |
| 화면을 떠나지 않고 서버 로직 수행 | Screen action + Action Button | screens.actions, triggers | 59 | Account_Check_Pipeline_Screen | Next, Get Records, back again |
| 트리거 레코드의 필드 설정 | 저장 전 Flow, Assignment to $Record | triggerType RecordBeforeSave | any | Opportunity_Before_Save_Set_Next_Step | After-save Update Records on $Record |
| 메시지로 저장 차단 | Custom Error | customErrors | 59 | Opportunity_Before_Save_Set_Next_Step | After-save compensation |
| 관련 필드가 변경될 때만 실행 | Entry conditions, filterFormula with ISCHANGED, "only when updated to meet the condition" | start | 55 (formula) | Opportunity_Before_Save_Set_Next_Step, Opportunity_Closed_Won_Handover | 첫 번째 엘리먼트로 Decision |
| 사용자가 기다릴 필요 없는 Callout, 이메일, 관련 없는 DML | Asynchronous path | scheduledPaths AsyncAfterCommit | 53 | Opportunity_Closed_Won_Handover | 모든 것을 동기적으로 |
| 레코드 날짜 전후 작업 | Scheduled path | scheduledPaths RecordField | 51 | Opportunity_Closed_Won_Handover | 예약 트리거 Flow가 기한 레코드를 폴링 |
| 플랫폼 이벤트에 반응 | Platform event-triggered flow | triggerType PlatformEvent | 49 | Order_Event_Create_Task | Flow 로직 시작을 위해 작성된 Apex 트리거 |
| 이벤트가 도착할 때까지 일시 중지 | Wait element with a platform event | waits | any | Order_Wait_For_Confirmation | Polling |
| Agentforce 에이전트를 위한 Flow 로직 | 설명된 입력 및 출력이 있는 자동 실행 Flow | variables description | any | Case_Get_Status_For_Agent | Invocable Apex wrapper |
| 하나의 오브젝트에 대한 여러 Flow 간 순서 | Trigger Order | triggerOrder | 54 | Opportunity_Closed_Won_Handover | 생성 순서에 의존 |
| REST API 호출 | HTTP Callout action | actionCalls (Builder-generated) | see integration reference | none | Callout만을 위해 작성된 Apex |
Transform은 저장 전 Flow에서 허용되지 않습니다(배포 오류). 저장 전(Before-save)이 Transform보다 우선하므로, 트리거 레코드의 값은 저장 전으로 유지되며, Sum이 필요한 경우 저장 후 Transform + 두 번째 저장 대신 E3 하에서 Loop를 사용합니다. 위의 다른 모든 사항은 해당 개념이 있는 모든 Flow 유형에서 작동하며, 도메인 참조에 예외가 나열됩니다.
이스케이프 조건
레거시 패턴은 다음 조건 중 하나가 성립하는 경우에만 올바릅니다. Loop의 <description>에 Escape: E<n> <reason> 형식으로 선언하고, 인도물에도 명시합니다.
| Id | 허용 대상 | 성립 조건 |
|---|---|---|
| E1 | Loop | 각 항목이 단일 값만 허용하는 액션, 하위 Flow 또는 Apex 플러그인에 대한 자체 호출이 필요합니다. Loop 본문에는 해당 호출이 포함됩니다. |
| E2 | Loop | 항목의 결과가 합계나 개수 이상의 이전 항목(예: 실행 잔액, 할당, 시퀀스 번호, 라운드 로빈)에 따라 달라집니다. |
| E3 | Loop | 저장 전 Flow에 Sum이 필요합니다(Transform이 허용되지 않음). 의도적인 결정입니다. 인메모리 Loop가 저장 후 두 번째 저장보다 저렴하기 때문입니다. Count는 Filter + AssignCount를 대신 사용합니다. |
| E4 | 동기 경로 작업 | 동일한 트랜잭션의 이후 엘리먼트가 결과를 읽거나, 사용자가 저장 완료 전에 결과를 봐야 합니다. |
| E5 | 반응형 또는 최신 화면 기능 미사용 | 명명된 임베딩 표면이 이를 지원하지 않습니다: Salesforce Classic 런타임, Slack(제한된 구성 요소 세트), 또는 반응형 문서에서 비반응형으로 나열하는 구성 요소. |
| E6 | 기존 레거시 패턴 유지 | 감사 범위만 해당: 해당 Flow는 요청받은 변경 사항의 범위를 벗어납니다. 새 Flow나 재작성된 Flow에는 절대 적용되지 않습니다. |
다음은 이스케이프 조건으로 간주되지 않습니다:
- "이 엘리먼트가 이 조직에 있는지 확인할 수 없습니다." (규칙 2 적용, API 버전 확인 후 배포 검증)
- "XML이 확실하지 않습니다." (예제 복사)
- "Loop가 더 간단하거나 명확합니다."
- "항목별 조건 값." (Transform 수식에서
IF()사용) - "필터링과 매핑을 한 번에." (Filter 후 Transform)
- "표면이 지원하지 않을 수도 있습니다." (표면 이름을 명시하거나 열린 결정으로 나열, 알 수 없는 표면은 E5가 아님)
- Loop 내부의 DML 또는 Get Records. 어떤 이스케이프도 이를 허용하지 않습니다.
가장 간단한 충분한 엘리먼트를 사용하십시오. 즉, 필터링만 필요하면 Filter 단독, 옵션 목록이 고정되어 있으면 정적 선택, 호출자가 하나인 로직에 하위 Flow는 불필요합니다.
확인 후 주장
- 사용 가능 여부: 조직 API 버전을 테이블과 대조합니다. 라이선스 기반 기능(Agentforce, Einstein, Data 360, 일부 오케스트레이션 에디션)은 조직이 확인할 때까지 가정으로 처리하고 그렇게 명시합니다.
- 설계나 감사 결과를 변경하는 한도 및 GA 상태: 공식 출처(help.salesforce.com, developer.salesforce.com)를 인용합니다. 도메인 참조에 검증된 숫자가 있으므로 메모리에서 숫자를 인용하지 마십시오.
오류 처리
- CLI 누락 또는 조직 연결 불가: '검증되지 않음' 레이블이 지정된 메타데이터 또는 빌드 스펙을 인도하고 그 사실을 명시합니다.
- 검증 실패: 정확한 메시지에 따라 수정하고, 체커와 검증을 다시 실행합니다. 도메인 참조에는 지금까지 발견된 배포 오류가 나열되어 있습니다.
- 조직에 기능 없음(API 버전, 에디션, 라이선스): 테이블의 가장 가까운 지원 행을 사용하고, 차이점과 이스케이프를 명시합니다.
참조
작업에 필요한 것만 읽으십시오:
- org-conventions.md: 팀의 결정 사항으로, 기본값보다 우선합니다.
- collections.md: Filter, Sort, Transform (map, sum, count, join), bulk DML, loops.
- screens.md: choice sets, reactive screens, validation, screen actions, embedding.
- record-triggered.md: entry conditions, filter formula, ISCHANGED, before-save vs after-save, trigger order, platform events.
- agent-actions.md: Agentforce 에이전트용 Flow 작성.
- legacy-migration.md: Process Builder 및 워크플로우 규칙 매핑.
- delivery.md: 감사 보고서, 빌드 스펙 및 인도 체크리스트 형식.
- limits-reference.md: 각 엘리먼트의 검증된 플랫폼 한도.
- integration.md: HTTP Callout, 외부 서비스.